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