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