brintos

brintos / linux-shallow public Read only

0
0
Text · 32.3 KiB · 5cf0e8c Raw
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