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