1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved
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,
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>
19 #include <linux/platform_device.h>
20 #include <linux/device.h>
22 #include <linux/interrupt.h>
23 #include <linux/ioport.h>
24 #include <soc/tegra/fuse.h>
25 #include <soc/tegra/tegra-cbb.h>
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
33 #define FABRIC_MN_MASTER_ERR_EN_0 0x200
34 #define FABRIC_MN_MASTER_ERR_FORCE_0 0x204
35 #define FABRIC_MN_MASTER_ERR_STATUS_0 0x208
36 #define FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0 0x20c
38 #define FABRIC_MN_MASTER_LOG_ERR_STATUS_0 0x300
39 #define FABRIC_MN_MASTER_LOG_ADDR_LOW_0 0x304
40 #define FABRIC_MN_MASTER_LOG_ADDR_HIGH_0 0x308
41 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0 0x30c
42 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0 0x310
43 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0 0x314
44 #define FABRIC_MN_MASTER_LOG_USER_BITS0_0 0x318
46 #define AXI_SLV_TIMEOUT_STATUS_0_0 0x8
47 #define APB_BLOCK_TMO_STATUS_0 0xc00
48 #define APB_BLOCK_NUM_TMO_OFFSET 0x20
50 #define FAB_EM_EL_MSTRID GENMASK(29, 24)
51 #define FAB_EM_EL_VQC GENMASK(17, 16)
52 #define FAB_EM_EL_GRPSEC GENMASK(14, 8)
53 #define FAB_EM_EL_FALCONSEC GENMASK(1, 0)
55 #define FAB_EM_EL_FABID GENMASK(20, 16)
56 #define FAB_EM_EL_SLAVEID GENMASK(7, 0)
58 #define FAB_EM_EL_ACCESSID GENMASK(7, 0)
60 #define FAB_EM_EL_AXCACHE GENMASK(27, 24)
61 #define FAB_EM_EL_AXPROT GENMASK(22, 20)
62 #define FAB_EM_EL_BURSTLENGTH GENMASK(19, 12)
63 #define FAB_EM_EL_BURSTTYPE GENMASK(9, 8)
64 #define FAB_EM_EL_BEATSIZE GENMASK(6, 4)
65 #define FAB_EM_EL_ACCESSTYPE GENMASK(0, 0)
67 #define USRBITS_MSTR_ID GENMASK(29, 24)
69 #define REQ_SOCKET_ID GENMASK(27, 24)
71 #define CCPLEX_MSTRID 0x1
72 #define FIREWALL_APERTURE_SZ 0x10000
73 /* Write firewall check enable */
76 enum tegra234_cbb_fabric_ids
{
88 struct tegra234_slave_lookup
{
93 struct tegra234_cbb_fabric
{
95 phys_addr_t off_mask_erd
;
96 phys_addr_t firewall_base
;
97 unsigned int firewall_ctl
;
98 unsigned int firewall_wr_ctl
;
99 const char * const *master_id
;
100 unsigned int notifier_offset
;
101 const struct tegra_cbb_error
*errors
;
102 const int max_errors
;
103 const struct tegra234_slave_lookup
*slave_map
;
104 const int max_slaves
;
107 struct tegra234_cbb
{
108 struct tegra_cbb base
;
110 const struct tegra234_cbb_fabric
*fabric
;
111 struct resource
*res
;
128 static inline struct tegra234_cbb
*to_tegra234_cbb(struct tegra_cbb
*cbb
)
130 return container_of(cbb
, struct tegra234_cbb
, base
);
133 static LIST_HEAD(cbb_list
);
134 static DEFINE_SPINLOCK(cbb_lock
);
137 tegra234_cbb_write_access_allowed(struct platform_device
*pdev
, struct tegra234_cbb
*cbb
)
141 if (!cbb
->fabric
->firewall_base
||
142 !cbb
->fabric
->firewall_ctl
||
143 !cbb
->fabric
->firewall_wr_ctl
) {
144 dev_info(&pdev
->dev
, "SoC data missing for firewall\n");
148 if ((cbb
->fabric
->firewall_ctl
> FIREWALL_APERTURE_SZ
) ||
149 (cbb
->fabric
->firewall_wr_ctl
> FIREWALL_APERTURE_SZ
)) {
150 dev_err(&pdev
->dev
, "wrong firewall offset value\n");
154 val
= readl(cbb
->regs
+ cbb
->fabric
->firewall_base
+ cbb
->fabric
->firewall_ctl
);
156 * If the firewall check feature for allowing or blocking the
157 * write accesses through the firewall of a fabric is disabled
158 * then CCPLEX can write to the registers of that fabric.
164 * If the firewall check is enabled then check whether CCPLEX
165 * has write access to the fabric's error notifier registers
167 val
= readl(cbb
->regs
+ cbb
->fabric
->firewall_base
+ cbb
->fabric
->firewall_wr_ctl
);
168 if (val
& (BIT(CCPLEX_MSTRID
)))
174 static void tegra234_cbb_fault_enable(struct tegra_cbb
*cbb
)
176 struct tegra234_cbb
*priv
= to_tegra234_cbb(cbb
);
179 addr
= priv
->regs
+ priv
->fabric
->notifier_offset
;
180 writel(0x1ff, addr
+ FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0
);
184 static void tegra234_cbb_error_clear(struct tegra_cbb
*cbb
)
186 struct tegra234_cbb
*priv
= to_tegra234_cbb(cbb
);
188 writel(0x3f, priv
->mon
+ FABRIC_MN_MASTER_ERR_STATUS_0
);
192 static u32
tegra234_cbb_get_status(struct tegra_cbb
*cbb
)
194 struct tegra234_cbb
*priv
= to_tegra234_cbb(cbb
);
198 addr
= priv
->regs
+ priv
->fabric
->notifier_offset
;
199 value
= readl(addr
+ FABRIC_EN_CFG_STATUS_0_0
);
205 static void tegra234_cbb_mask_serror(struct tegra234_cbb
*cbb
)
207 writel(0x1, cbb
->regs
+ cbb
->fabric
->off_mask_erd
);
211 static u32
tegra234_cbb_get_tmo_slv(void __iomem
*addr
)
215 timeout
= readl(addr
);
219 static void tegra234_cbb_tmo_slv(struct seq_file
*file
, const char *slave
, void __iomem
*addr
,
222 tegra_cbb_print_err(file
, "\t %s : %#x\n", slave
, status
);
225 static void tegra234_cbb_lookup_apbslv(struct seq_file
*file
, const char *slave
,
228 unsigned int block
= 0;
233 status
= tegra234_cbb_get_tmo_slv(base
);
235 tegra_cbb_print_err(file
, "\t %s_BLOCK_TMO_STATUS : %#x\n", slave
, status
);
238 if (status
& BIT(0)) {
239 u32 timeout
, clients
, client
= 0;
241 addr
= base
+ APB_BLOCK_NUM_TMO_OFFSET
+ (block
* 4);
242 timeout
= tegra234_cbb_get_tmo_slv(addr
);
246 if (timeout
& BIT(0)) {
247 if (clients
!= 0xffffffff)
248 clients
&= BIT(client
);
250 sprintf(name
, "%s_BLOCK%d_TMO", slave
, block
);
252 tegra234_cbb_tmo_slv(file
, name
, addr
, clients
);
265 static void tegra234_lookup_slave_timeout(struct seq_file
*file
, struct tegra234_cbb
*cbb
,
266 u8 slave_id
, u8 fab_id
)
268 const struct tegra234_slave_lookup
*map
= cbb
->fabric
->slave_map
;
272 * 1) Get slave node name and address mapping using slave_id.
273 * 2) Check if the timed out slave node is APB or AXI.
274 * 3) If AXI, then print timeout register and reset axi slave
275 * using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register.
276 * 4) If APB, then perform an additional lookup to find the client
278 * a) Get block number from the index of set bit in
279 * <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register.
280 * b) Get address of register repective to block number i.e.
281 * <FABRIC>_SN_AXI2APB_<>_BLOCK<index-set-bit>_TMO_0.
282 * c) Read the register in above step to get client_id which
283 * timed out as per the set bits.
284 * d) Reset the timedout client and print details.
285 * e) Goto step-a till all bits are set.
288 addr
= cbb
->regs
+ map
[slave_id
].offset
;
290 if (strstr(map
[slave_id
].name
, "AXI2APB")) {
291 addr
+= APB_BLOCK_TMO_STATUS_0
;
293 tegra234_cbb_lookup_apbslv(file
, map
[slave_id
].name
, addr
);
298 addr
+= AXI_SLV_TIMEOUT_STATUS_0_0
;
300 status
= tegra234_cbb_get_tmo_slv(addr
);
302 sprintf(name
, "%s_SLV_TIMEOUT_STATUS", map
[slave_id
].name
);
303 tegra234_cbb_tmo_slv(file
, name
, addr
, status
);
308 static void tegra234_cbb_print_error(struct seq_file
*file
, struct tegra234_cbb
*cbb
, u32 status
,
311 unsigned int type
= 0;
313 if (status
& (status
- 1))
314 tegra_cbb_print_err(file
, "\t Multiple type of errors reported\n");
317 if (type
>= cbb
->fabric
->max_errors
) {
318 tegra_cbb_print_err(file
, "\t Wrong type index:%u, status:%u\n",
324 tegra_cbb_print_err(file
, "\t Error Code\t\t: %s\n",
325 cbb
->fabric
->errors
[type
].code
);
334 if (type
>= cbb
->fabric
->max_errors
) {
335 tegra_cbb_print_err(file
, "\t Wrong type index:%u, overflow:%u\n",
341 tegra_cbb_print_err(file
, "\t Overflow\t\t: Multiple %s\n",
342 cbb
->fabric
->errors
[type
].code
);
349 static void print_errlog_err(struct seq_file
*file
, struct tegra234_cbb
*cbb
)
351 u8 cache_type
, prot_type
, burst_length
, mstr_id
, grpsec
, vqc
, falconsec
, beat_size
;
352 u8 access_type
, access_id
, requester_socket_id
, local_socket_id
, slave_id
, fab_id
;
353 char fabric_name
[20];
354 bool is_numa
= false;
357 if (num_possible_nodes() > 1)
360 mstr_id
= FIELD_GET(FAB_EM_EL_MSTRID
, cbb
->mn_user_bits
);
361 vqc
= FIELD_GET(FAB_EM_EL_VQC
, cbb
->mn_user_bits
);
362 grpsec
= FIELD_GET(FAB_EM_EL_GRPSEC
, cbb
->mn_user_bits
);
363 falconsec
= FIELD_GET(FAB_EM_EL_FALCONSEC
, cbb
->mn_user_bits
);
366 * For SOC with multiple NUMA nodes, print cross socket access
367 * errors only if initiator/master_id is CCPLEX, CPMU or GPU.
370 local_socket_id
= numa_node_id();
371 requester_socket_id
= FIELD_GET(REQ_SOCKET_ID
, cbb
->mn_attr2
);
373 if (requester_socket_id
!= local_socket_id
) {
374 if ((mstr_id
!= 0x1) && (mstr_id
!= 0x2) && (mstr_id
!= 0xB))
379 fab_id
= FIELD_GET(FAB_EM_EL_FABID
, cbb
->mn_attr2
);
380 slave_id
= FIELD_GET(FAB_EM_EL_SLAVEID
, cbb
->mn_attr2
);
382 access_id
= FIELD_GET(FAB_EM_EL_ACCESSID
, cbb
->mn_attr1
);
384 cache_type
= FIELD_GET(FAB_EM_EL_AXCACHE
, cbb
->mn_attr0
);
385 prot_type
= FIELD_GET(FAB_EM_EL_AXPROT
, cbb
->mn_attr0
);
386 burst_length
= FIELD_GET(FAB_EM_EL_BURSTLENGTH
, cbb
->mn_attr0
);
387 burst_type
= FIELD_GET(FAB_EM_EL_BURSTTYPE
, cbb
->mn_attr0
);
388 beat_size
= FIELD_GET(FAB_EM_EL_BEATSIZE
, cbb
->mn_attr0
);
389 access_type
= FIELD_GET(FAB_EM_EL_ACCESSTYPE
, cbb
->mn_attr0
);
391 tegra_cbb_print_err(file
, "\n");
392 if (cbb
->type
< cbb
->fabric
->max_errors
)
393 tegra_cbb_print_err(file
, "\t Error Code\t\t: %s\n",
394 cbb
->fabric
->errors
[cbb
->type
].code
);
396 tegra_cbb_print_err(file
, "\t Wrong type index:%u\n", cbb
->type
);
398 tegra_cbb_print_err(file
, "\t MASTER_ID\t\t: %s\n", cbb
->fabric
->master_id
[mstr_id
]);
399 tegra_cbb_print_err(file
, "\t Address\t\t: %#llx\n", cbb
->access
);
401 tegra_cbb_print_cache(file
, cache_type
);
402 tegra_cbb_print_prot(file
, prot_type
);
404 tegra_cbb_print_err(file
, "\t Access_Type\t\t: %s", (access_type
) ? "Write\n" : "Read\n");
405 tegra_cbb_print_err(file
, "\t Access_ID\t\t: %#x", access_id
);
407 if (fab_id
== PSC_FAB_ID
)
408 strcpy(fabric_name
, "psc-fabric");
409 else if (fab_id
== FSI_FAB_ID
)
410 strcpy(fabric_name
, "fsi-fabric");
412 strcpy(fabric_name
, cbb
->fabric
->name
);
415 tegra_cbb_print_err(file
, "\t Requester_Socket_Id\t: %#x\n",
416 requester_socket_id
);
417 tegra_cbb_print_err(file
, "\t Local_Socket_Id\t: %#x\n",
419 tegra_cbb_print_err(file
, "\t No. of NUMA_NODES\t: %#x\n",
420 num_possible_nodes());
423 tegra_cbb_print_err(file
, "\t Fabric\t\t: %s\n", fabric_name
);
424 tegra_cbb_print_err(file
, "\t Slave_Id\t\t: %#x\n", slave_id
);
425 tegra_cbb_print_err(file
, "\t Burst_length\t\t: %#x\n", burst_length
);
426 tegra_cbb_print_err(file
, "\t Burst_type\t\t: %#x\n", burst_type
);
427 tegra_cbb_print_err(file
, "\t Beat_size\t\t: %#x\n", beat_size
);
428 tegra_cbb_print_err(file
, "\t VQC\t\t\t: %#x\n", vqc
);
429 tegra_cbb_print_err(file
, "\t GRPSEC\t\t: %#x\n", grpsec
);
430 tegra_cbb_print_err(file
, "\t FALCONSEC\t\t: %#x\n", falconsec
);
432 if ((fab_id
== PSC_FAB_ID
) || (fab_id
== FSI_FAB_ID
))
435 if (slave_id
>= cbb
->fabric
->max_slaves
) {
436 tegra_cbb_print_err(file
, "\t Invalid slave_id:%d\n", slave_id
);
440 if (!strcmp(cbb
->fabric
->errors
[cbb
->type
].code
, "TIMEOUT_ERR")) {
441 tegra234_lookup_slave_timeout(file
, cbb
, slave_id
, fab_id
);
445 tegra_cbb_print_err(file
, "\t Slave\t\t\t: %s\n", cbb
->fabric
->slave_map
[slave_id
].name
);
448 static int print_errmonX_info(struct seq_file
*file
, struct tegra234_cbb
*cbb
)
450 u32 overflow
, status
, error
;
452 status
= readl(cbb
->mon
+ FABRIC_MN_MASTER_ERR_STATUS_0
);
454 pr_err("Error Notifier received a spurious notification\n");
458 if (status
== 0xffffffff) {
459 pr_err("CBB registers returning all 1's which is invalid\n");
463 overflow
= readl(cbb
->mon
+ FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0
);
465 tegra234_cbb_print_error(file
, cbb
, status
, overflow
);
467 error
= readl(cbb
->mon
+ FABRIC_MN_MASTER_LOG_ERR_STATUS_0
);
469 pr_info("Error Monitor doesn't have Error Logger\n");
476 if (error
& BIT(0)) {
479 hi
= readl(cbb
->mon
+ FABRIC_MN_MASTER_LOG_ADDR_HIGH_0
);
480 lo
= readl(cbb
->mon
+ FABRIC_MN_MASTER_LOG_ADDR_LOW_0
);
482 cbb
->access
= (u64
)hi
<< 32 | lo
;
484 cbb
->mn_attr0
= readl(cbb
->mon
+ FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0
);
485 cbb
->mn_attr1
= readl(cbb
->mon
+ FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0
);
486 cbb
->mn_attr2
= readl(cbb
->mon
+ FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0
);
487 cbb
->mn_user_bits
= readl(cbb
->mon
+ FABRIC_MN_MASTER_LOG_USER_BITS0_0
);
489 print_errlog_err(file
, cbb
);
499 static int print_err_notifier(struct seq_file
*file
, struct tegra234_cbb
*cbb
, u32 status
)
501 unsigned int index
= 0;
504 pr_crit("**************************************\n");
505 pr_crit("CPU:%d, Error:%s, Errmon:%d\n", smp_processor_id(),
506 cbb
->fabric
->name
, status
);
509 if (status
& BIT(0)) {
510 unsigned int notifier
= cbb
->fabric
->notifier_offset
;
511 u32 hi
, lo
, mask
= BIT(index
);
515 writel(mask
, cbb
->regs
+ notifier
+ FABRIC_EN_CFG_ADDR_INDEX_0_0
);
516 hi
= readl(cbb
->regs
+ notifier
+ FABRIC_EN_CFG_ADDR_HI_0
);
517 lo
= readl(cbb
->regs
+ notifier
+ FABRIC_EN_CFG_ADDR_LOW_0
);
519 addr
= (u64
)hi
<< 32 | lo
;
521 offset
= addr
- cbb
->res
->start
;
522 cbb
->mon
= cbb
->regs
+ offset
;
523 cbb
->mask
= BIT(index
);
525 err
= print_errmonX_info(file
, cbb
);
526 tegra234_cbb_error_clear(&cbb
->base
);
535 tegra_cbb_print_err(file
, "\t**************************************\n");
539 #ifdef CONFIG_DEBUG_FS
540 static DEFINE_MUTEX(cbb_debugfs_mutex
);
542 static int tegra234_cbb_debugfs_show(struct tegra_cbb
*cbb
, struct seq_file
*file
, void *data
)
546 mutex_lock(&cbb_debugfs_mutex
);
548 list_for_each_entry(cbb
, &cbb_list
, node
) {
549 struct tegra234_cbb
*priv
= to_tegra234_cbb(cbb
);
552 status
= tegra_cbb_get_status(&priv
->base
);
554 err
= print_err_notifier(file
, priv
, status
);
560 mutex_unlock(&cbb_debugfs_mutex
);
566 * Handler for CBB errors
568 static irqreturn_t
tegra234_cbb_isr(int irq
, void *data
)
570 bool is_inband_err
= false;
571 struct tegra_cbb
*cbb
;
576 spin_lock_irqsave(&cbb_lock
, flags
);
578 list_for_each_entry(cbb
, &cbb_list
, node
) {
579 struct tegra234_cbb
*priv
= to_tegra234_cbb(cbb
);
580 u32 status
= tegra_cbb_get_status(cbb
);
582 if (status
&& (irq
== priv
->sec_irq
)) {
583 tegra_cbb_print_err(NULL
, "CPU:%d, Error: %s@0x%llx, irq=%d\n",
584 smp_processor_id(), priv
->fabric
->name
,
585 priv
->res
->start
, irq
);
587 err
= print_err_notifier(NULL
, priv
, status
);
592 * If illegal request is from CCPLEX(id:0x1) master then call WARN()
594 if (priv
->fabric
->off_mask_erd
) {
595 mstr_id
= FIELD_GET(USRBITS_MSTR_ID
, priv
->mn_user_bits
);
596 if (mstr_id
== CCPLEX_MSTRID
)
603 spin_unlock_irqrestore(&cbb_lock
, flags
);
604 WARN_ON(is_inband_err
);
609 * Register handler for CBB_SECURE interrupt for reporting errors
611 static int tegra234_cbb_interrupt_enable(struct tegra_cbb
*cbb
)
613 struct tegra234_cbb
*priv
= to_tegra234_cbb(cbb
);
616 int err
= devm_request_irq(cbb
->dev
, priv
->sec_irq
, tegra234_cbb_isr
, 0,
617 dev_name(cbb
->dev
), priv
);
619 dev_err(cbb
->dev
, "failed to register interrupt %u: %d\n", priv
->sec_irq
,
628 static void tegra234_cbb_error_enable(struct tegra_cbb
*cbb
)
630 tegra_cbb_fault_enable(cbb
);
633 static const struct tegra_cbb_ops tegra234_cbb_ops
= {
634 .get_status
= tegra234_cbb_get_status
,
635 .error_clear
= tegra234_cbb_error_clear
,
636 .fault_enable
= tegra234_cbb_fault_enable
,
637 .error_enable
= tegra234_cbb_error_enable
,
638 .interrupt_enable
= tegra234_cbb_interrupt_enable
,
639 #ifdef CONFIG_DEBUG_FS
640 .debugfs_show
= tegra234_cbb_debugfs_show
,
644 static const char * const tegra234_master_id
[] = {
652 [0x07] = "TSECA_NONSECURE",
653 [0x08] = "TSECA_LIGHTSECURE",
654 [0x09] = "TSECA_HEAVYSECURE",
655 [0x0a] = "CORESIGHT",
658 [0x0d] = "JTAGM_DFT",
661 [0x10] = "PSC_FW_USER",
662 [0x11] = "PSC_FW_SUPERVISOR",
663 [0x12] = "PSC_FW_MACHINE",
665 [0x14] = "BPMP_BOOT",
666 [0x15] = "NVDEC_NONSECURE",
667 [0x16] = "NVDEC_LIGHTSECURE",
668 [0x17] = "NVDEC_HEAVYSECURE",
669 [0x18] = "CBB_INTERNAL",
673 static const struct tegra_cbb_error tegra234_cbb_errors
[] = {
676 .desc
= "Slave being accessed responded with an error"
678 .code
= "DECODE_ERR",
679 .desc
= "Attempt to access an address hole"
681 .code
= "FIREWALL_ERR",
682 .desc
= "Attempt to access a region which is firewall protected"
684 .code
= "TIMEOUT_ERR",
685 .desc
= "No response returned by slave"
687 .code
= "PWRDOWN_ERR",
688 .desc
= "Attempt to access a portion of fabric that is powered down"
690 .code
= "UNSUPPORTED_ERR",
691 .desc
= "Attempt to access a slave through an unsupported access"
695 static const struct tegra234_slave_lookup tegra234_aon_slave_map
[] = {
696 { "AXI2APB", 0x00000 },
702 static const struct tegra234_cbb_fabric tegra234_aon_fabric
= {
703 .name
= "aon-fabric",
704 .master_id
= tegra234_master_id
,
705 .slave_map
= tegra234_aon_slave_map
,
706 .max_slaves
= ARRAY_SIZE(tegra234_aon_slave_map
),
707 .errors
= tegra234_cbb_errors
,
708 .max_errors
= ARRAY_SIZE(tegra234_cbb_errors
),
709 .notifier_offset
= 0x17000,
710 .firewall_base
= 0x30000,
711 .firewall_ctl
= 0x8d0,
712 .firewall_wr_ctl
= 0x8c8,
715 static const struct tegra234_slave_lookup tegra234_bpmp_slave_map
[] = {
716 { "AXI2APB", 0x00000 },
723 static const struct tegra234_cbb_fabric tegra234_bpmp_fabric
= {
724 .name
= "bpmp-fabric",
725 .master_id
= tegra234_master_id
,
726 .slave_map
= tegra234_bpmp_slave_map
,
727 .max_slaves
= ARRAY_SIZE(tegra234_bpmp_slave_map
),
728 .errors
= tegra234_cbb_errors
,
729 .max_errors
= ARRAY_SIZE(tegra234_cbb_errors
),
730 .notifier_offset
= 0x19000,
731 .firewall_base
= 0x30000,
732 .firewall_ctl
= 0x8f0,
733 .firewall_wr_ctl
= 0x8e8,
736 static const struct tegra234_slave_lookup tegra234_cbb_slave_map
[] = {
740 { "HOST1X", 0x43000 },
744 { "PCIE_C1", 0x47000 },
745 { "PCIE_C2", 0x48000 },
746 { "PCIE_C3", 0x49000 },
747 { "PCIE_C0", 0x4a000 },
748 { "PCIE_C4", 0x4b000 },
750 { "SMMU0", 0x4d000 },
751 { "SMMU1", 0x4e000 },
752 { "SMMU2", 0x4f000 },
753 { "SMMU3", 0x50000 },
754 { "SMMU4", 0x51000 },
755 { "PCIE_C10", 0x52000 },
756 { "PCIE_C7", 0x53000 },
757 { "PCIE_C8", 0x54000 },
758 { "PCIE_C9", 0x55000 },
759 { "PCIE_C5", 0x56000 },
760 { "PCIE_C6", 0x57000 },
764 { "AXI2APB_1", 0x70000 },
765 { "AXI2APB_10", 0x71000 },
766 { "AXI2APB_11", 0x72000 },
767 { "AXI2APB_12", 0x73000 },
768 { "AXI2APB_13", 0x74000 },
769 { "AXI2APB_14", 0x75000 },
770 { "AXI2APB_15", 0x76000 },
771 { "AXI2APB_16", 0x77000 },
772 { "AXI2APB_17", 0x78000 },
773 { "AXI2APB_18", 0x79000 },
774 { "AXI2APB_19", 0x7a000 },
775 { "AXI2APB_2", 0x7b000 },
776 { "AXI2APB_20", 0x7c000 },
777 { "AXI2APB_21", 0x7d000 },
778 { "AXI2APB_22", 0x7e000 },
779 { "AXI2APB_23", 0x7f000 },
780 { "AXI2APB_25", 0x80000 },
781 { "AXI2APB_26", 0x81000 },
782 { "AXI2APB_27", 0x82000 },
783 { "AXI2APB_28", 0x83000 },
784 { "AXI2APB_29", 0x84000 },
785 { "AXI2APB_30", 0x85000 },
786 { "AXI2APB_31", 0x86000 },
787 { "AXI2APB_32", 0x87000 },
788 { "AXI2APB_33", 0x88000 },
789 { "AXI2APB_34", 0x89000 },
790 { "AXI2APB_35", 0x92000 },
791 { "AXI2APB_4", 0x8b000 },
792 { "AXI2APB_5", 0x8c000 },
793 { "AXI2APB_6", 0x8d000 },
794 { "AXI2APB_7", 0x8e000 },
795 { "AXI2APB_8", 0x8f000 },
796 { "AXI2APB_9", 0x90000 },
797 { "AXI2APB_3", 0x91000 },
800 static const struct tegra234_cbb_fabric tegra234_cbb_fabric
= {
801 .name
= "cbb-fabric",
802 .master_id
= tegra234_master_id
,
803 .slave_map
= tegra234_cbb_slave_map
,
804 .max_slaves
= ARRAY_SIZE(tegra234_cbb_slave_map
),
805 .errors
= tegra234_cbb_errors
,
806 .max_errors
= ARRAY_SIZE(tegra234_cbb_errors
),
807 .notifier_offset
= 0x60000,
808 .off_mask_erd
= 0x3a004,
809 .firewall_base
= 0x10000,
810 .firewall_ctl
= 0x23f0,
811 .firewall_wr_ctl
= 0x23e8,
814 static const struct tegra234_slave_lookup tegra234_common_slave_map
[] = {
815 { "AXI2APB", 0x00000 },
823 static const struct tegra234_cbb_fabric tegra234_dce_fabric
= {
824 .name
= "dce-fabric",
825 .master_id
= tegra234_master_id
,
826 .slave_map
= tegra234_common_slave_map
,
827 .max_slaves
= ARRAY_SIZE(tegra234_common_slave_map
),
828 .errors
= tegra234_cbb_errors
,
829 .max_errors
= ARRAY_SIZE(tegra234_cbb_errors
),
830 .notifier_offset
= 0x19000,
831 .firewall_base
= 0x30000,
832 .firewall_ctl
= 0x290,
833 .firewall_wr_ctl
= 0x288,
836 static const struct tegra234_cbb_fabric tegra234_rce_fabric
= {
837 .name
= "rce-fabric",
838 .master_id
= tegra234_master_id
,
839 .slave_map
= tegra234_common_slave_map
,
840 .max_slaves
= ARRAY_SIZE(tegra234_common_slave_map
),
841 .errors
= tegra234_cbb_errors
,
842 .max_errors
= ARRAY_SIZE(tegra234_cbb_errors
),
843 .notifier_offset
= 0x19000,
844 .firewall_base
= 0x30000,
845 .firewall_ctl
= 0x290,
846 .firewall_wr_ctl
= 0x288,
849 static const struct tegra234_cbb_fabric tegra234_sce_fabric
= {
850 .name
= "sce-fabric",
851 .master_id
= tegra234_master_id
,
852 .slave_map
= tegra234_common_slave_map
,
853 .max_slaves
= ARRAY_SIZE(tegra234_common_slave_map
),
854 .errors
= tegra234_cbb_errors
,
855 .max_errors
= ARRAY_SIZE(tegra234_cbb_errors
),
856 .notifier_offset
= 0x19000,
857 .firewall_base
= 0x30000,
858 .firewall_ctl
= 0x290,
859 .firewall_wr_ctl
= 0x288,
862 static const char * const tegra241_master_id
[] = {
867 [0x4] = "PSC_FW_USER",
868 [0x5] = "PSC_FW_SUPERVISOR",
869 [0x6] = "PSC_FW_MACHINE",
876 [0xd ... 0x3f] = "RSVD"
880 * Possible causes for Slave and Timeout errors.
882 * Slave being accessed responded with an error. Slave could return
883 * an error for various cases :
884 * Unsupported access, clamp setting when power gated, register
885 * level firewall(SCR), address hole within the slave, etc
888 * No response returned by slave. Can be due to slave being clock
889 * gated, under reset, powered down or slave inability to respond
890 * for an internal slave issue
892 static const struct tegra_cbb_error tegra241_cbb_errors
[] = {
895 .desc
= "Slave being accessed responded with an error."
897 .code
= "DECODE_ERR",
898 .desc
= "Attempt to access an address hole or Reserved region of memory."
900 .code
= "FIREWALL_ERR",
901 .desc
= "Attempt to access a region which is firewalled."
903 .code
= "TIMEOUT_ERR",
904 .desc
= "No response returned by slave."
906 .code
= "PWRDOWN_ERR",
907 .desc
= "Attempt to access a portion of the fabric that is powered down."
909 .code
= "UNSUPPORTED_ERR",
910 .desc
= "Attempt to access a slave through an unsupported access."
912 .code
= "POISON_ERR",
913 .desc
= "Slave responds with poison error to indicate error in data."
933 .code
= "NO_SUCH_ADDRESS_ERR",
934 .desc
= "The address belongs to the pri_target range but there is no register "
935 "implemented at the address."
938 .desc
= "Attempt to update a PRI task when the current task has still not "
941 .code
= "EXTERNAL_ERR",
942 .desc
= "Indicates that an external PRI register access met with an error due to "
943 "any issue in the unit."
946 .desc
= "Applicable to PRI index aperture pair, when the programmed index is "
947 "outside the range defined in the manual."
950 .desc
= "Target in Reset Error: Attempt to access a SubPri or external PRI "
951 "register but they are in reset."
953 .code
= "REGISTER_RST_ERR",
954 .desc
= "Attempt to access a PRI register but the register is partial or "
955 "completely in reset."
957 .code
= "POWER_GATED_ERR",
958 .desc
= "Returned by external PRI client when the external access goes to a power "
961 .code
= "SUBPRI_FS_ERR",
962 .desc
= "Subpri is floorswept: Attempt to access a subpri through the main pri "
963 "target but subPri logic is floorswept."
965 .code
= "SUBPRI_CLK_OFF_ERR",
966 .desc
= "Subpri clock is off: Attempt to access a subpri through the main pri "
967 "target but subPris clock is gated/off."
971 static const struct tegra234_slave_lookup tegra241_cbb_slave_map
[] = {
973 { "PCIE_C8", 0x51000 },
974 { "PCIE_C9", 0x52000 },
989 { "AXI2APB_1", 0x70000 },
990 { "AXI2APB_10", 0x71000 },
991 { "AXI2APB_11", 0x72000 },
992 { "AXI2APB_12", 0x73000 },
993 { "AXI2APB_13", 0x74000 },
994 { "AXI2APB_14", 0x75000 },
995 { "AXI2APB_15", 0x76000 },
996 { "AXI2APB_16", 0x77000 },
997 { "AXI2APB_17", 0x78000 },
998 { "AXI2APB_18", 0x79000 },
999 { "AXI2APB_19", 0x7a000 },
1000 { "AXI2APB_2", 0x7b000 },
1001 { "AXI2APB_20", 0x7c000 },
1002 { "AXI2APB_4", 0x87000 },
1003 { "AXI2APB_5", 0x88000 },
1004 { "AXI2APB_6", 0x89000 },
1005 { "AXI2APB_7", 0x8a000 },
1006 { "AXI2APB_8", 0x8b000 },
1007 { "AXI2APB_9", 0x8c000 },
1008 { "AXI2APB_3", 0x8d000 },
1009 { "AXI2APB_21", 0x7d000 },
1010 { "AXI2APB_22", 0x7e000 },
1011 { "AXI2APB_23", 0x7f000 },
1012 { "AXI2APB_24", 0x80000 },
1013 { "AXI2APB_25", 0x81000 },
1014 { "AXI2APB_26", 0x82000 },
1015 { "AXI2APB_27", 0x83000 },
1016 { "AXI2APB_28", 0x84000 },
1017 { "PCIE_C4", 0x53000 },
1018 { "PCIE_C5", 0x54000 },
1019 { "PCIE_C6", 0x55000 },
1020 { "PCIE_C7", 0x56000 },
1021 { "PCIE_C2", 0x57000 },
1022 { "PCIE_C3", 0x58000 },
1023 { "PCIE_C0", 0x59000 },
1024 { "PCIE_C1", 0x5a000 },
1025 { "CCPLEX", 0x50000 },
1026 { "AXI2APB_29", 0x85000 },
1027 { "AXI2APB_30", 0x86000 },
1028 { "CBB_CENTRAL", 0x00000 },
1029 { "AXI2APB_31", 0x8E000 },
1030 { "AXI2APB_32", 0x8F000 },
1033 static const struct tegra234_cbb_fabric tegra241_cbb_fabric
= {
1034 .name
= "cbb-fabric",
1035 .master_id
= tegra241_master_id
,
1036 .slave_map
= tegra241_cbb_slave_map
,
1037 .max_slaves
= ARRAY_SIZE(tegra241_cbb_slave_map
),
1038 .errors
= tegra241_cbb_errors
,
1039 .max_errors
= ARRAY_SIZE(tegra241_cbb_errors
),
1040 .notifier_offset
= 0x60000,
1041 .off_mask_erd
= 0x40004,
1042 .firewall_base
= 0x20000,
1043 .firewall_ctl
= 0x2370,
1044 .firewall_wr_ctl
= 0x2368,
1047 static const struct tegra234_slave_lookup tegra241_bpmp_slave_map
[] = {
1048 { "RSVD", 0x00000 },
1049 { "RSVD", 0x00000 },
1050 { "RSVD", 0x00000 },
1053 { "AXI2APB", 0x00000 },
1054 { "DBB0", 0x17000 },
1055 { "DBB1", 0x18000 },
1058 static const struct tegra234_cbb_fabric tegra241_bpmp_fabric
= {
1059 .name
= "bpmp-fabric",
1060 .master_id
= tegra241_master_id
,
1061 .slave_map
= tegra241_bpmp_slave_map
,
1062 .max_slaves
= ARRAY_SIZE(tegra241_bpmp_slave_map
),
1063 .errors
= tegra241_cbb_errors
,
1064 .max_errors
= ARRAY_SIZE(tegra241_cbb_errors
),
1065 .notifier_offset
= 0x19000,
1066 .firewall_base
= 0x30000,
1067 .firewall_ctl
= 0x8f0,
1068 .firewall_wr_ctl
= 0x8e8,
1071 static const struct of_device_id tegra234_cbb_dt_ids
[] = {
1072 { .compatible
= "nvidia,tegra234-cbb-fabric", .data
= &tegra234_cbb_fabric
},
1073 { .compatible
= "nvidia,tegra234-aon-fabric", .data
= &tegra234_aon_fabric
},
1074 { .compatible
= "nvidia,tegra234-bpmp-fabric", .data
= &tegra234_bpmp_fabric
},
1075 { .compatible
= "nvidia,tegra234-dce-fabric", .data
= &tegra234_dce_fabric
},
1076 { .compatible
= "nvidia,tegra234-rce-fabric", .data
= &tegra234_rce_fabric
},
1077 { .compatible
= "nvidia,tegra234-sce-fabric", .data
= &tegra234_sce_fabric
},
1080 MODULE_DEVICE_TABLE(of
, tegra234_cbb_dt_ids
);
1082 struct tegra234_cbb_acpi_uid
{
1085 const struct tegra234_cbb_fabric
*fabric
;
1088 static const struct tegra234_cbb_acpi_uid tegra234_cbb_acpi_uids
[] = {
1089 { "NVDA1070", "1", &tegra241_cbb_fabric
},
1090 { "NVDA1070", "2", &tegra241_bpmp_fabric
},
1095 tegra234_cbb_fabric
*tegra234_cbb_acpi_get_fabric(struct acpi_device
*adev
)
1097 const struct tegra234_cbb_acpi_uid
*entry
;
1099 for (entry
= tegra234_cbb_acpi_uids
; entry
->hid
; entry
++) {
1100 if (acpi_dev_hid_uid_match(adev
, entry
->hid
, entry
->uid
))
1101 return entry
->fabric
;
1107 static const struct acpi_device_id tegra241_cbb_acpi_ids
[] = {
1111 MODULE_DEVICE_TABLE(acpi
, tegra241_cbb_acpi_ids
);
1113 static int tegra234_cbb_probe(struct platform_device
*pdev
)
1115 const struct tegra234_cbb_fabric
*fabric
;
1116 struct tegra234_cbb
*cbb
;
1117 unsigned long flags
= 0;
1120 if (pdev
->dev
.of_node
) {
1121 fabric
= of_device_get_match_data(&pdev
->dev
);
1123 struct acpi_device
*device
= ACPI_COMPANION(&pdev
->dev
);
1127 fabric
= tegra234_cbb_acpi_get_fabric(device
);
1129 dev_err(&pdev
->dev
, "no device match found\n");
1134 cbb
= devm_kzalloc(&pdev
->dev
, sizeof(*cbb
), GFP_KERNEL
);
1138 INIT_LIST_HEAD(&cbb
->base
.node
);
1139 cbb
->base
.ops
= &tegra234_cbb_ops
;
1140 cbb
->base
.dev
= &pdev
->dev
;
1141 cbb
->fabric
= fabric
;
1143 cbb
->regs
= devm_platform_get_and_ioremap_resource(pdev
, 0, &cbb
->res
);
1144 if (IS_ERR(cbb
->regs
))
1145 return PTR_ERR(cbb
->regs
);
1147 err
= tegra_cbb_get_irq(pdev
, NULL
, &cbb
->sec_irq
);
1151 platform_set_drvdata(pdev
, cbb
);
1154 * Don't enable error reporting for a Fabric if write to it's registers
1155 * is blocked by CBB firewall.
1157 if (!tegra234_cbb_write_access_allowed(pdev
, cbb
)) {
1158 dev_info(&pdev
->dev
, "error reporting not enabled due to firewall\n");
1162 spin_lock_irqsave(&cbb_lock
, flags
);
1163 list_add(&cbb
->base
.node
, &cbb_list
);
1164 spin_unlock_irqrestore(&cbb_lock
, flags
);
1166 /* set ERD bit to mask SError and generate interrupt to report error */
1167 if (cbb
->fabric
->off_mask_erd
)
1168 tegra234_cbb_mask_serror(cbb
);
1170 return tegra_cbb_register(&cbb
->base
);
1173 static int __maybe_unused
tegra234_cbb_resume_noirq(struct device
*dev
)
1175 struct tegra234_cbb
*cbb
= dev_get_drvdata(dev
);
1177 tegra234_cbb_error_enable(&cbb
->base
);
1179 dev_dbg(dev
, "%s resumed\n", cbb
->fabric
->name
);
1184 static const struct dev_pm_ops tegra234_cbb_pm
= {
1185 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL
, tegra234_cbb_resume_noirq
)
1188 static struct platform_driver tegra234_cbb_driver
= {
1189 .probe
= tegra234_cbb_probe
,
1191 .name
= "tegra234-cbb",
1192 .of_match_table
= tegra234_cbb_dt_ids
,
1193 .acpi_match_table
= tegra241_cbb_acpi_ids
,
1194 .pm
= &tegra234_cbb_pm
,
1198 static int __init
tegra234_cbb_init(void)
1200 return platform_driver_register(&tegra234_cbb_driver
);
1202 pure_initcall(tegra234_cbb_init
);
1204 static void __exit
tegra234_cbb_exit(void)
1206 platform_driver_unregister(&tegra234_cbb_driver
);
1208 module_exit(tegra234_cbb_exit
);
1210 MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234");