Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc/tegra: cbb: Add driver for Tegra234 CBB 2.0

Adding driver to handle errors from CBB version 2.0 which is used in
Tegra234 SoC. The driver prints debug information about failed
transaction on receiving interrupt from the error notifier. The error
notifier collates the interrupts from various error monitor blocks and
presents a single interrupt to the SoC interrupt controller.

For timeout errors, the driver also does the lookup to find timed out
clients and prints their client ID. Drivers for hardware that needs to
be reset on timeout will have to call BPMP from the client IP's driver.
BPMP firmware will also clear the timeout bit after resetting the IP
so that next transactions are send to them after reset.

Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Sumit Gupta and committed by
Thierry Reding
fc2f151d b7134422

+848 -1
+1 -1
drivers/soc/tegra/Kconfig
··· 165 165 166 166 config SOC_TEGRA_CBB 167 167 tristate "Tegra driver to handle error from CBB" 168 - depends on ARCH_TEGRA_194_SOC 168 + depends on ARCH_TEGRA_194_SOC || ARCH_TEGRA_234_SOC 169 169 default y 170 170 help 171 171 Support for handling error from Tegra Control Backbone(CBB).
+1
drivers/soc/tegra/cbb/Makefile
··· 5 5 ifdef CONFIG_SOC_TEGRA_CBB 6 6 obj-y += tegra-cbb.o 7 7 obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra194-cbb.o 8 + obj-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra234-cbb.o 8 9 endif
+846
drivers/soc/tegra/cbb/tegra234-cbb.c
··· 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/clk.h> 14 + #include <linux/cpufeature.h> 15 + #include <linux/debugfs.h> 16 + #include <linux/module.h> 17 + #include <linux/of.h> 18 + #include <linux/of_device.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/device.h> 21 + #include <linux/io.h> 22 + #include <linux/of_irq.h> 23 + #include <linux/of_address.h> 24 + #include <linux/interrupt.h> 25 + #include <linux/ioport.h> 26 + #include <linux/version.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 + enum tegra234_cbb_fabric_ids { 75 + CBB_FAB_ID, 76 + SCE_FAB_ID, 77 + RCE_FAB_ID, 78 + DCE_FAB_ID, 79 + AON_FAB_ID, 80 + PSC_FAB_ID, 81 + BPMP_FAB_ID, 82 + FSI_FAB_ID, 83 + MAX_FAB_ID, 84 + }; 85 + 86 + struct tegra234_slave_lookup { 87 + const char *name; 88 + unsigned int offset; 89 + }; 90 + 91 + struct tegra234_cbb_fabric { 92 + const char *name; 93 + phys_addr_t off_mask_erd; 94 + bool erd_mask_inband_err; 95 + const char * const *master_id; 96 + unsigned int notifier_offset; 97 + const struct tegra_cbb_error *errors; 98 + const struct tegra234_slave_lookup *slave_map; 99 + }; 100 + 101 + struct tegra234_cbb { 102 + struct tegra_cbb base; 103 + 104 + const struct tegra234_cbb_fabric *fabric; 105 + struct resource *res; 106 + void __iomem *regs; 107 + 108 + int num_intr; 109 + int sec_irq; 110 + 111 + /* record */ 112 + void __iomem *mon; 113 + unsigned int type; 114 + u32 mask; 115 + u64 access; 116 + u32 mn_attr0; 117 + u32 mn_attr1; 118 + u32 mn_attr2; 119 + u32 mn_user_bits; 120 + }; 121 + 122 + static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb) 123 + { 124 + return container_of(cbb, struct tegra234_cbb, base); 125 + } 126 + 127 + static LIST_HEAD(cbb_list); 128 + static DEFINE_SPINLOCK(cbb_lock); 129 + 130 + static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb) 131 + { 132 + struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 133 + void __iomem *addr; 134 + 135 + addr = priv->regs + priv->fabric->notifier_offset; 136 + writel(0x1ff, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0); 137 + dsb(sy); 138 + } 139 + 140 + static void tegra234_cbb_error_clear(struct tegra_cbb *cbb) 141 + { 142 + struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 143 + 144 + writel(0x3f, priv->mon + FABRIC_MN_MASTER_ERR_STATUS_0); 145 + dsb(sy); 146 + } 147 + 148 + static u32 tegra234_cbb_get_status(struct tegra_cbb *cbb) 149 + { 150 + struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 151 + void __iomem *addr; 152 + u32 value; 153 + 154 + addr = priv->regs + priv->fabric->notifier_offset; 155 + value = readl(addr + FABRIC_EN_CFG_STATUS_0_0); 156 + dsb(sy); 157 + 158 + return value; 159 + } 160 + 161 + static void tegra234_cbb_mask_serror(struct tegra234_cbb *cbb) 162 + { 163 + writel(0x1, cbb->regs + cbb->fabric->off_mask_erd); 164 + dsb(sy); 165 + } 166 + 167 + static u32 tegra234_cbb_get_tmo_slv(void __iomem *addr) 168 + { 169 + u32 timeout; 170 + 171 + timeout = readl(addr); 172 + return timeout; 173 + } 174 + 175 + static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *slave, void __iomem *addr, 176 + u32 status) 177 + { 178 + tegra_cbb_print_err(file, "\t %s : %#x\n", slave, status); 179 + } 180 + 181 + static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave, 182 + void __iomem *base) 183 + { 184 + unsigned int block = 0; 185 + void __iomem *addr; 186 + char name[64]; 187 + u32 status; 188 + 189 + status = tegra234_cbb_get_tmo_slv(base); 190 + if (status) 191 + tegra_cbb_print_err(file, "\t %s_BLOCK_TMO_STATUS : %#x\n", slave, status); 192 + 193 + while (status) { 194 + if (status & BIT(0)) { 195 + u32 timeout, clients, client = 0; 196 + 197 + addr = base + APB_BLOCK_NUM_TMO_OFFSET + (block * 4); 198 + timeout = tegra234_cbb_get_tmo_slv(addr); 199 + clients = timeout; 200 + 201 + while (timeout) { 202 + if (timeout & BIT(0)) { 203 + if (clients != 0xffffffff) 204 + clients &= BIT(client); 205 + 206 + sprintf(name, "%s_BLOCK%d_TMO", slave, block); 207 + 208 + tegra234_cbb_tmo_slv(file, name, addr, clients); 209 + } 210 + 211 + timeout >>= 1; 212 + client++; 213 + } 214 + } 215 + 216 + status >>= 1; 217 + block++; 218 + } 219 + } 220 + 221 + static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234_cbb *cbb, 222 + u8 slave_id, u8 fab_id) 223 + { 224 + const struct tegra234_slave_lookup *map = cbb->fabric->slave_map; 225 + void __iomem *addr; 226 + 227 + /* 228 + * 1) Get slave node name and address mapping using slave_id. 229 + * 2) Check if the timed out slave node is APB or AXI. 230 + * 3) If AXI, then print timeout register and reset axi slave 231 + * using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register. 232 + * 4) If APB, then perform an additional lookup to find the client 233 + * which timed out. 234 + * a) Get block number from the index of set bit in 235 + * <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register. 236 + * b) Get address of register repective to block number i.e. 237 + * <FABRIC>_SN_AXI2APB_<>_BLOCK<index-set-bit>_TMO_0. 238 + * c) Read the register in above step to get client_id which 239 + * timed out as per the set bits. 240 + * d) Reset the timedout client and print details. 241 + * e) Goto step-a till all bits are set. 242 + */ 243 + 244 + addr = cbb->regs + map[slave_id].offset; 245 + 246 + if (strstr(map[slave_id].name, "AXI2APB")) { 247 + addr += APB_BLOCK_TMO_STATUS_0; 248 + 249 + tegra234_cbb_lookup_apbslv(file, map[slave_id].name, addr); 250 + } else { 251 + char name[64]; 252 + u32 status; 253 + 254 + addr += AXI_SLV_TIMEOUT_STATUS_0_0; 255 + 256 + status = tegra234_cbb_get_tmo_slv(addr); 257 + if (status) { 258 + sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[slave_id].name); 259 + tegra234_cbb_tmo_slv(file, name, addr, status); 260 + } 261 + } 262 + } 263 + 264 + static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb *cbb, u32 status, 265 + u32 overflow) 266 + { 267 + unsigned int type = 0; 268 + 269 + if (status & (status - 1)) 270 + tegra_cbb_print_err(file, "\t Multiple type of errors reported\n"); 271 + 272 + while (status) { 273 + if (status & 0x1) 274 + tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n", 275 + cbb->fabric->errors[type].code); 276 + 277 + status >>= 1; 278 + type++; 279 + } 280 + 281 + type = 0; 282 + 283 + while (overflow) { 284 + if (overflow & 0x1) 285 + tegra_cbb_print_err(file, "\t Overflow\t\t: Multiple %s\n", 286 + cbb->fabric->errors[type].code); 287 + 288 + overflow >>= 1; 289 + type++; 290 + } 291 + } 292 + 293 + static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) 294 + { 295 + u8 cache_type, prot_type, burst_length, mstr_id, grpsec, vqc, falconsec, beat_size; 296 + u8 access_type, access_id, slave_id, fab_id, burst_type; 297 + char fabric_name[20]; 298 + 299 + mstr_id = FIELD_GET(FAB_EM_EL_MSTRID, cbb->mn_user_bits); 300 + vqc = FIELD_GET(FAB_EM_EL_VQC, cbb->mn_user_bits); 301 + grpsec = FIELD_GET(FAB_EM_EL_GRPSEC, cbb->mn_user_bits); 302 + falconsec = FIELD_GET(FAB_EM_EL_FALCONSEC, cbb->mn_user_bits); 303 + 304 + fab_id = FIELD_GET(FAB_EM_EL_FABID, cbb->mn_attr2); 305 + slave_id = FIELD_GET(FAB_EM_EL_SLAVEID, cbb->mn_attr2); 306 + 307 + access_id = FIELD_GET(FAB_EM_EL_ACCESSID, cbb->mn_attr1); 308 + 309 + cache_type = FIELD_GET(FAB_EM_EL_AXCACHE, cbb->mn_attr0); 310 + prot_type = FIELD_GET(FAB_EM_EL_AXPROT, cbb->mn_attr0); 311 + burst_length = FIELD_GET(FAB_EM_EL_BURSTLENGTH, cbb->mn_attr0); 312 + burst_type = FIELD_GET(FAB_EM_EL_BURSTTYPE, cbb->mn_attr0); 313 + beat_size = FIELD_GET(FAB_EM_EL_BEATSIZE, cbb->mn_attr0); 314 + access_type = FIELD_GET(FAB_EM_EL_ACCESSTYPE, cbb->mn_attr0); 315 + 316 + tegra_cbb_print_err(file, "\n"); 317 + tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n", 318 + cbb->fabric->errors[cbb->type].code); 319 + 320 + tegra_cbb_print_err(file, "\t MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]); 321 + tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access); 322 + 323 + tegra_cbb_print_cache(file, cache_type); 324 + tegra_cbb_print_prot(file, prot_type); 325 + 326 + tegra_cbb_print_err(file, "\t Access_Type\t\t: %s", (access_type) ? "Write\n" : "Read\n"); 327 + tegra_cbb_print_err(file, "\t Access_ID\t\t: %#x", access_id); 328 + 329 + if (fab_id == PSC_FAB_ID) 330 + strcpy(fabric_name, "psc-fabric"); 331 + else if (fab_id == FSI_FAB_ID) 332 + strcpy(fabric_name, "fsi-fabric"); 333 + else 334 + strcpy(fabric_name, cbb->fabric->name); 335 + 336 + tegra_cbb_print_err(file, "\t Fabric\t\t: %s\n", fabric_name); 337 + tegra_cbb_print_err(file, "\t Slave_Id\t\t: %#x\n", slave_id); 338 + tegra_cbb_print_err(file, "\t Burst_length\t\t: %#x\n", burst_length); 339 + tegra_cbb_print_err(file, "\t Burst_type\t\t: %#x\n", burst_type); 340 + tegra_cbb_print_err(file, "\t Beat_size\t\t: %#x\n", beat_size); 341 + tegra_cbb_print_err(file, "\t VQC\t\t\t: %#x\n", vqc); 342 + tegra_cbb_print_err(file, "\t GRPSEC\t\t: %#x\n", grpsec); 343 + tegra_cbb_print_err(file, "\t FALCONSEC\t\t: %#x\n", falconsec); 344 + 345 + if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID)) 346 + return; 347 + 348 + if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) { 349 + tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id); 350 + return; 351 + } 352 + 353 + tegra_cbb_print_err(file, "\t Slave\t\t\t: %s\n", cbb->fabric->slave_map[slave_id].name); 354 + } 355 + 356 + static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb) 357 + { 358 + u32 overflow, status, error; 359 + 360 + status = readl(cbb->mon + FABRIC_MN_MASTER_ERR_STATUS_0); 361 + if (!status) { 362 + pr_err("Error Notifier received a spurious notification\n"); 363 + return -ENODATA; 364 + } 365 + 366 + if (status == 0xffffffff) { 367 + pr_err("CBB registers returning all 1's which is invalid\n"); 368 + return -EINVAL; 369 + } 370 + 371 + overflow = readl(cbb->mon + FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0); 372 + 373 + tegra234_cbb_print_error(file, cbb, status, overflow); 374 + 375 + error = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ERR_STATUS_0); 376 + if (!error) { 377 + pr_info("Error Monitor doesn't have Error Logger\n"); 378 + return -EINVAL; 379 + } 380 + 381 + cbb->type = 0; 382 + 383 + while (error) { 384 + if (error & BIT(0)) { 385 + u32 hi, lo; 386 + 387 + hi = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_HIGH_0); 388 + lo = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_LOW_0); 389 + 390 + cbb->access = (u64)hi << 32 | lo; 391 + 392 + cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0); 393 + cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0); 394 + cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0); 395 + cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_MASTER_LOG_USER_BITS0_0); 396 + 397 + print_errlog_err(file, cbb); 398 + } 399 + 400 + cbb->type++; 401 + error >>= 1; 402 + } 403 + 404 + return 0; 405 + } 406 + 407 + static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u32 status) 408 + { 409 + unsigned int index = 0; 410 + int err; 411 + 412 + pr_crit("**************************************\n"); 413 + pr_crit("CPU:%d, Error:%s, Errmon:%d\n", smp_processor_id(), 414 + cbb->fabric->name, status); 415 + 416 + while (status) { 417 + if (status & BIT(0)) { 418 + unsigned int notifier = cbb->fabric->notifier_offset; 419 + u32 hi, lo, mask = BIT(index); 420 + phys_addr_t addr; 421 + u64 offset; 422 + 423 + writel(mask, cbb->regs + notifier + FABRIC_EN_CFG_ADDR_INDEX_0_0); 424 + hi = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_HI_0); 425 + lo = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_LOW_0); 426 + 427 + addr = (u64)hi << 32 | lo; 428 + 429 + offset = addr - cbb->res->start; 430 + cbb->mon = cbb->regs + offset; 431 + cbb->mask = BIT(index); 432 + 433 + err = print_errmonX_info(file, cbb); 434 + tegra234_cbb_error_clear(&cbb->base); 435 + if (err) 436 + return err; 437 + } 438 + 439 + status >>= 1; 440 + index++; 441 + } 442 + 443 + tegra_cbb_print_err(file, "\t**************************************\n"); 444 + return 0; 445 + } 446 + 447 + #ifdef CONFIG_DEBUG_FS 448 + static DEFINE_MUTEX(cbb_debugfs_mutex); 449 + 450 + static int tegra234_cbb_debugfs_show(struct tegra_cbb *cbb, struct seq_file *file, void *data) 451 + { 452 + int err = 0; 453 + 454 + mutex_lock(&cbb_debugfs_mutex); 455 + 456 + list_for_each_entry(cbb, &cbb_list, node) { 457 + struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 458 + u32 status; 459 + 460 + status = tegra_cbb_get_status(&priv->base); 461 + if (status) { 462 + err = print_err_notifier(file, priv, status); 463 + if (err) 464 + break; 465 + } 466 + } 467 + 468 + mutex_unlock(&cbb_debugfs_mutex); 469 + return err; 470 + } 471 + #endif 472 + 473 + /* 474 + * Handler for CBB errors 475 + */ 476 + static irqreturn_t tegra234_cbb_isr(int irq, void *data) 477 + { 478 + bool is_inband_err = false; 479 + struct tegra_cbb *cbb; 480 + unsigned long flags; 481 + u8 mstr_id; 482 + int err; 483 + 484 + spin_lock_irqsave(&cbb_lock, flags); 485 + 486 + list_for_each_entry(cbb, &cbb_list, node) { 487 + struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 488 + u32 status = tegra_cbb_get_status(cbb); 489 + 490 + if (status && (irq == priv->sec_irq)) { 491 + tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@%llx, irq=%d\n", 492 + smp_processor_id(), priv->fabric->name, 493 + priv->res->start, irq); 494 + 495 + err = print_err_notifier(NULL, priv, status); 496 + if (err) 497 + goto unlock; 498 + 499 + mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits); 500 + 501 + /* 502 + * If illegal request is from CCPLEX(id:0x1) master then call BUG() to 503 + * crash system. 504 + */ 505 + if ((mstr_id == 0x1) && priv->fabric->off_mask_erd) 506 + is_inband_err = 1; 507 + } 508 + } 509 + 510 + unlock: 511 + spin_unlock_irqrestore(&cbb_lock, flags); 512 + WARN_ON(is_inband_err); 513 + return IRQ_HANDLED; 514 + } 515 + 516 + /* 517 + * Register handler for CBB_SECURE interrupt for reporting errors 518 + */ 519 + static int tegra234_cbb_interrupt_enable(struct tegra_cbb *cbb) 520 + { 521 + struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 522 + 523 + if (priv->sec_irq) { 524 + int err = devm_request_irq(cbb->dev, priv->sec_irq, tegra234_cbb_isr, 0, 525 + dev_name(cbb->dev), priv); 526 + if (err) { 527 + dev_err(cbb->dev, "failed to register interrupt %u: %d\n", priv->sec_irq, 528 + err); 529 + return err; 530 + } 531 + } 532 + 533 + return 0; 534 + } 535 + 536 + static void tegra234_cbb_error_enable(struct tegra_cbb *cbb) 537 + { 538 + tegra_cbb_fault_enable(cbb); 539 + } 540 + 541 + static const struct tegra_cbb_ops tegra234_cbb_ops = { 542 + .get_status = tegra234_cbb_get_status, 543 + .error_clear = tegra234_cbb_error_clear, 544 + .fault_enable = tegra234_cbb_fault_enable, 545 + .error_enable = tegra234_cbb_error_enable, 546 + .interrupt_enable = tegra234_cbb_interrupt_enable, 547 + #ifdef CONFIG_DEBUG_FS 548 + .debugfs_show = tegra234_cbb_debugfs_show, 549 + #endif 550 + }; 551 + 552 + static const char * const tegra234_master_id[] = { 553 + [0x00] = "TZ", 554 + [0x01] = "CCPLEX", 555 + [0x02] = "CCPMU", 556 + [0x03] = "BPMP_FW", 557 + [0x04] = "AON", 558 + [0x05] = "SCE", 559 + [0x06] = "GPCDMA_P", 560 + [0x07] = "TSECA_NONSECURE", 561 + [0x08] = "TSECA_LIGHTSECURE", 562 + [0x09] = "TSECA_HEAVYSECURE", 563 + [0x0a] = "CORESIGHT", 564 + [0x0b] = "APE", 565 + [0x0c] = "PEATRANS", 566 + [0x0d] = "JTAGM_DFT", 567 + [0x0e] = "RCE", 568 + [0x0f] = "DCE", 569 + [0x10] = "PSC_FW_USER", 570 + [0x11] = "PSC_FW_SUPERVISOR", 571 + [0x12] = "PSC_FW_MACHINE", 572 + [0x13] = "PSC_BOOT", 573 + [0x14] = "BPMP_BOOT", 574 + [0x15] = "NVDEC_NONSECURE", 575 + [0x16] = "NVDEC_LIGHTSECURE", 576 + [0x17] = "NVDEC_HEAVYSECURE", 577 + [0x18] = "CBB_INTERNAL", 578 + [0x19] = "RSVD" 579 + }; 580 + 581 + static const struct tegra_cbb_error tegra234_cbb_errors[] = { 582 + { 583 + .code = "SLAVE_ERR", 584 + .desc = "Slave being accessed responded with an error" 585 + }, { 586 + .code = "DECODE_ERR", 587 + .desc = "Attempt to access an address hole" 588 + }, { 589 + .code = "FIREWALL_ERR", 590 + .desc = "Attempt to access a region which is firewall protected" 591 + }, { 592 + .code = "TIMEOUT_ERR", 593 + .desc = "No response returned by slave" 594 + }, { 595 + .code = "PWRDOWN_ERR", 596 + .desc = "Attempt to access a portion of fabric that is powered down" 597 + }, { 598 + .code = "UNSUPPORTED_ERR", 599 + .desc = "Attempt to access a slave through an unsupported access" 600 + } 601 + }; 602 + 603 + static const struct tegra234_slave_lookup tegra234_aon_slave_map[] = { 604 + { "AXI2APB", 0x00000 }, 605 + { "AST", 0x14000 }, 606 + { "CBB", 0x15000 }, 607 + { "CPU", 0x16000 }, 608 + }; 609 + 610 + static const struct tegra234_cbb_fabric tegra234_aon_fabric = { 611 + .name = "aon-fabric", 612 + .master_id = tegra234_master_id, 613 + .slave_map = tegra234_aon_slave_map, 614 + .errors = tegra234_cbb_errors, 615 + .notifier_offset = 0x17000, 616 + }; 617 + 618 + static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = { 619 + { "AXI2APB", 0x00000 }, 620 + { "AST0", 0x15000 }, 621 + { "AST1", 0x16000 }, 622 + { "CBB", 0x17000 }, 623 + { "CPU", 0x18000 }, 624 + }; 625 + 626 + static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = { 627 + .name = "bpmp-fabric", 628 + .master_id = tegra234_master_id, 629 + .slave_map = tegra234_bpmp_slave_map, 630 + .errors = tegra234_cbb_errors, 631 + .notifier_offset = 0x19000, 632 + }; 633 + 634 + static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = { 635 + { "AON", 0x40000 }, 636 + { "BPMP", 0x41000 }, 637 + { "CBB", 0x42000 }, 638 + { "HOST1X", 0x43000 }, 639 + { "STM", 0x44000 }, 640 + { "FSI", 0x45000 }, 641 + { "PSC", 0x46000 }, 642 + { "PCIE_C1", 0x47000 }, 643 + { "PCIE_C2", 0x48000 }, 644 + { "PCIE_C3", 0x49000 }, 645 + { "PCIE_C0", 0x4a000 }, 646 + { "PCIE_C4", 0x4b000 }, 647 + { "GPU", 0x4c000 }, 648 + { "SMMU0", 0x4d000 }, 649 + { "SMMU1", 0x4e000 }, 650 + { "SMMU2", 0x4f000 }, 651 + { "SMMU3", 0x50000 }, 652 + { "SMMU4", 0x51000 }, 653 + { "PCIE_C10", 0x52000 }, 654 + { "PCIE_C7", 0x53000 }, 655 + { "PCIE_C8", 0x54000 }, 656 + { "PCIE_C9", 0x55000 }, 657 + { "PCIE_C5", 0x56000 }, 658 + { "PCIE_C6", 0x57000 }, 659 + { "DCE", 0x58000 }, 660 + { "RCE", 0x59000 }, 661 + { "SCE", 0x5a000 }, 662 + { "AXI2APB_1", 0x70000 }, 663 + { "AXI2APB_10", 0x71000 }, 664 + { "AXI2APB_11", 0x72000 }, 665 + { "AXI2APB_12", 0x73000 }, 666 + { "AXI2APB_13", 0x74000 }, 667 + { "AXI2APB_14", 0x75000 }, 668 + { "AXI2APB_15", 0x76000 }, 669 + { "AXI2APB_16", 0x77000 }, 670 + { "AXI2APB_17", 0x78000 }, 671 + { "AXI2APB_18", 0x79000 }, 672 + { "AXI2APB_19", 0x7a000 }, 673 + { "AXI2APB_2", 0x7b000 }, 674 + { "AXI2APB_20", 0x7c000 }, 675 + { "AXI2APB_21", 0x7d000 }, 676 + { "AXI2APB_22", 0x7e000 }, 677 + { "AXI2APB_23", 0x7f000 }, 678 + { "AXI2APB_25", 0x80000 }, 679 + { "AXI2APB_26", 0x81000 }, 680 + { "AXI2APB_27", 0x82000 }, 681 + { "AXI2APB_28", 0x83000 }, 682 + { "AXI2APB_29", 0x84000 }, 683 + { "AXI2APB_30", 0x85000 }, 684 + { "AXI2APB_31", 0x86000 }, 685 + { "AXI2APB_32", 0x87000 }, 686 + { "AXI2APB_33", 0x88000 }, 687 + { "AXI2APB_34", 0x89000 }, 688 + { "AXI2APB_35", 0x92000 }, 689 + { "AXI2APB_4", 0x8b000 }, 690 + { "AXI2APB_5", 0x8c000 }, 691 + { "AXI2APB_6", 0x8d000 }, 692 + { "AXI2APB_7", 0x8e000 }, 693 + { "AXI2APB_8", 0x8f000 }, 694 + { "AXI2APB_9", 0x90000 }, 695 + { "AXI2APB_3", 0x91000 }, 696 + }; 697 + 698 + static const struct tegra234_cbb_fabric tegra234_cbb_fabric = { 699 + .name = "cbb-fabric", 700 + .master_id = tegra234_master_id, 701 + .slave_map = tegra234_cbb_slave_map, 702 + .errors = tegra234_cbb_errors, 703 + .notifier_offset = 0x60000, 704 + .off_mask_erd = 0x3a004 705 + }; 706 + 707 + static const struct tegra234_slave_lookup tegra234_dce_slave_map[] = { 708 + { "AXI2APB", 0x00000 }, 709 + { "AST0", 0x15000 }, 710 + { "AST1", 0x16000 }, 711 + { "CPU", 0x18000 }, 712 + }; 713 + 714 + static const struct tegra234_cbb_fabric tegra234_dce_fabric = { 715 + .name = "dce-fabric", 716 + .master_id = tegra234_master_id, 717 + .slave_map = tegra234_dce_slave_map, 718 + .errors = tegra234_cbb_errors, 719 + .notifier_offset = 0x19000, 720 + }; 721 + 722 + static const struct tegra234_slave_lookup tegra234_rce_slave_map[] = { 723 + { "AXI2APB", 0x00000 }, 724 + { "AST0", 0x15000 }, 725 + { "AST1", 0x16000 }, 726 + { "CPU", 0x18000 }, 727 + }; 728 + 729 + static const struct tegra234_cbb_fabric tegra234_rce_fabric = { 730 + .name = "rce-fabric", 731 + .master_id = tegra234_master_id, 732 + .slave_map = tegra234_rce_slave_map, 733 + .errors = tegra234_cbb_errors, 734 + .notifier_offset = 0x19000, 735 + }; 736 + 737 + static const struct tegra234_slave_lookup tegra234_sce_slave_map[] = { 738 + { "AXI2APB", 0x00000 }, 739 + { "AST0", 0x15000 }, 740 + { "AST1", 0x16000 }, 741 + { "CBB", 0x17000 }, 742 + { "CPU", 0x18000 }, 743 + }; 744 + 745 + static const struct tegra234_cbb_fabric tegra234_sce_fabric = { 746 + .name = "sce-fabric", 747 + .master_id = tegra234_master_id, 748 + .slave_map = tegra234_sce_slave_map, 749 + .errors = tegra234_cbb_errors, 750 + .notifier_offset = 0x19000, 751 + }; 752 + 753 + static const struct of_device_id tegra234_cbb_dt_ids[] = { 754 + { .compatible = "nvidia,tegra234-cbb-fabric", .data = &tegra234_cbb_fabric }, 755 + { .compatible = "nvidia,tegra234-aon-fabric", .data = &tegra234_aon_fabric }, 756 + { .compatible = "nvidia,tegra234-bpmp-fabric", .data = &tegra234_bpmp_fabric }, 757 + { .compatible = "nvidia,tegra234-dce-fabric", .data = &tegra234_dce_fabric }, 758 + { .compatible = "nvidia,tegra234-rce-fabric", .data = &tegra234_rce_fabric }, 759 + { .compatible = "nvidia,tegra234-sce-fabric", .data = &tegra234_sce_fabric }, 760 + { /* sentinel */ }, 761 + }; 762 + MODULE_DEVICE_TABLE(of, tegra234_cbb_dt_ids); 763 + 764 + static int tegra234_cbb_probe(struct platform_device *pdev) 765 + { 766 + const struct tegra234_cbb_fabric *fabric; 767 + struct tegra234_cbb *cbb; 768 + unsigned long flags = 0; 769 + int err; 770 + 771 + fabric = of_device_get_match_data(&pdev->dev); 772 + 773 + cbb = devm_kzalloc(&pdev->dev, sizeof(*cbb), GFP_KERNEL); 774 + if (!cbb) 775 + return -ENOMEM; 776 + 777 + INIT_LIST_HEAD(&cbb->base.node); 778 + cbb->base.ops = &tegra234_cbb_ops; 779 + cbb->base.dev = &pdev->dev; 780 + cbb->fabric = fabric; 781 + 782 + cbb->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &cbb->res); 783 + if (IS_ERR(cbb->regs)) 784 + return PTR_ERR(cbb->regs); 785 + 786 + err = tegra_cbb_get_irq(pdev, NULL, &cbb->sec_irq); 787 + if (err) 788 + return err; 789 + 790 + platform_set_drvdata(pdev, cbb); 791 + 792 + spin_lock_irqsave(&cbb_lock, flags); 793 + list_add(&cbb->base.node, &cbb_list); 794 + spin_unlock_irqrestore(&cbb_lock, flags); 795 + 796 + /* set ERD bit to mask SError and generate interrupt to report error */ 797 + if (cbb->fabric->off_mask_erd) 798 + tegra234_cbb_mask_serror(cbb); 799 + 800 + return tegra_cbb_register(&cbb->base); 801 + } 802 + 803 + static int tegra234_cbb_remove(struct platform_device *pdev) 804 + { 805 + return 0; 806 + } 807 + 808 + static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) 809 + { 810 + struct tegra234_cbb *cbb = dev_get_drvdata(dev); 811 + 812 + tegra234_cbb_error_enable(&cbb->base); 813 + 814 + dev_dbg(dev, "%s resumed\n", cbb->fabric->name); 815 + 816 + return 0; 817 + } 818 + 819 + static const struct dev_pm_ops tegra234_cbb_pm = { 820 + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, tegra234_cbb_resume_noirq) 821 + }; 822 + 823 + static struct platform_driver tegra234_cbb_driver = { 824 + .probe = tegra234_cbb_probe, 825 + .remove = tegra234_cbb_remove, 826 + .driver = { 827 + .name = "tegra234-cbb", 828 + .of_match_table = tegra234_cbb_dt_ids, 829 + .pm = &tegra234_cbb_pm, 830 + }, 831 + }; 832 + 833 + static int __init tegra234_cbb_init(void) 834 + { 835 + return platform_driver_register(&tegra234_cbb_driver); 836 + } 837 + pure_initcall(tegra234_cbb_init); 838 + 839 + static void __exit tegra234_cbb_exit(void) 840 + { 841 + platform_driver_unregister(&tegra234_cbb_driver); 842 + } 843 + module_exit(tegra234_cbb_exit); 844 + 845 + MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234"); 846 + MODULE_LICENSE("GPL");