tegra234-cbb.c 32 KB

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