]> Git Repo - linux.git/blob - drivers/soc/tegra/cbb/tegra234-cbb.c
Linux 6.14-rc3
[linux.git] / drivers / soc / tegra / cbb / tegra234-cbb.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved
4  *
5  * The driver handles Error's from Control Backbone(CBB) version 2.0.
6  * generated due to illegal accesses. The driver prints debug information
7  * about failed transaction on receiving interrupt from Error Notifier.
8  * Error types supported by CBB2.0 are:
9  *   UNSUPPORTED_ERR, PWRDOWN_ERR, TIMEOUT_ERR, FIREWALL_ERR, DECODE_ERR,
10  *   SLAVE_ERR
11  */
12
13 #include <linux/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      0x0
28 #define FABRIC_EN_CFG_STATUS_0_0                0x40
29 #define FABRIC_EN_CFG_ADDR_INDEX_0_0            0x60
30 #define FABRIC_EN_CFG_ADDR_LOW_0                0x80
31 #define FABRIC_EN_CFG_ADDR_HI_0                 0x84
32
33 #define FABRIC_MN_MASTER_ERR_EN_0               0x200
34 #define FABRIC_MN_MASTER_ERR_FORCE_0            0x204
35 #define FABRIC_MN_MASTER_ERR_STATUS_0           0x208
36 #define FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0  0x20c
37
38 #define FABRIC_MN_MASTER_LOG_ERR_STATUS_0       0x300
39 #define FABRIC_MN_MASTER_LOG_ADDR_LOW_0         0x304
40 #define FABRIC_MN_MASTER_LOG_ADDR_HIGH_0        0x308
41 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0      0x30c
42 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0      0x310
43 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0      0x314
44 #define FABRIC_MN_MASTER_LOG_USER_BITS0_0       0x318
45
46 #define AXI_SLV_TIMEOUT_STATUS_0_0              0x8
47 #define APB_BLOCK_TMO_STATUS_0                  0xc00
48 #define APB_BLOCK_NUM_TMO_OFFSET                0x20
49
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                   0x1
72 #define FIREWALL_APERTURE_SZ            0x10000
73 /* Write firewall check enable */
74 #define WEN                             0x20000
75
76 enum 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
88 struct tegra234_slave_lookup {
89         const char *name;
90         unsigned int offset;
91 };
92
93 struct 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
107 struct 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
128 static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb)
129 {
130         return container_of(cbb, struct tegra234_cbb, base);
131 }
132
133 static LIST_HEAD(cbb_list);
134 static DEFINE_SPINLOCK(cbb_lock);
135
136 static bool
137 tegra234_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 the
157          * write accesses through the firewall of a fabric is disabled
158          * 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 CCPLEX
165          * has write access to the fabric's error notifier registers
166          */
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
174 static 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
184 static 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
192 static 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
205 static 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
211 static u32 tegra234_cbb_get_tmo_slv(void __iomem *addr)
212 {
213         u32 timeout;
214
215         timeout = readl(addr);
216         return timeout;
217 }
218
219 static 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
225 static 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
265 static 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 slave
275          *    using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register.
276          * 4) If APB, then perform an additional lookup to find the client
277          *    which timed out.
278          *      a) Get block number from the index of set bit in
279          *         <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register.
280          *      b) Get address of register respective 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 which
283          *         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
308 static 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
349 static 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 access
367          * 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         else
396                 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         else
412                 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
448 static 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
499 static 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_FS
540 static DEFINE_MUTEX(cbb_debugfs_mutex);
541
542 static 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 #endif
564
565 /*
566  * Handler for CBB errors
567  */
568 static 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
602 unlock:
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 errors
610  */
611 static 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
628 static void tegra234_cbb_error_enable(struct tegra_cbb *cbb)
629 {
630         tegra_cbb_fault_enable(cbb);
631 }
632
633 static 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_FS
640         .debugfs_show = tegra234_cbb_debugfs_show,
641 #endif
642 };
643
644 static 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
673 static 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
695 static const struct tegra234_slave_lookup tegra234_aon_slave_map[] = {
696         { "AXI2APB", 0x00000 },
697         { "AST",     0x14000 },
698         { "CBB",     0x15000 },
699         { "CPU",     0x16000 },
700 };
701
702 static 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
715 static 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
723 static 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
736 static 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
800 static 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
814 static 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
823 static 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
836 static 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
849 static 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
862 static 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 return
883  * an error for various cases :
884  *   Unsupported access, clamp setting when power gated, register
885  *   level firewall(SCR), address hole within the slave, etc
886  *
887  * TIMEOUT_ERR:
888  * No response returned by slave. Can be due to slave being clock
889  * gated, under reset, powered down or slave inability to respond
890  * for an internal slave issue
891  */
892 static 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
971 static 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
1033 static 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
1047 static 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
1058 static 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
1071 static 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 };
1080 MODULE_DEVICE_TABLE(of, tegra234_cbb_dt_ids);
1081
1082 struct tegra234_cbb_acpi_uid {
1083         const char *hid;
1084         const char *uid;
1085         const struct tegra234_cbb_fabric *fabric;
1086 };
1087
1088 static 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
1094 static const struct
1095 tegra234_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
1107 static const struct acpi_device_id tegra241_cbb_acpi_ids[] = {
1108         { "NVDA1070" },
1109         { },
1110 };
1111 MODULE_DEVICE_TABLE(acpi, tegra241_cbb_acpi_ids);
1112
1113 static 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 registers
1155          * 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
1173 static 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
1184 static const struct dev_pm_ops tegra234_cbb_pm = {
1185         SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, tegra234_cbb_resume_noirq)
1186 };
1187
1188 static 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
1198 static int __init tegra234_cbb_init(void)
1199 {
1200         return platform_driver_register(&tegra234_cbb_driver);
1201 }
1202 pure_initcall(tegra234_cbb_init);
1203
1204 static void __exit tegra234_cbb_exit(void)
1205 {
1206         platform_driver_unregister(&tegra234_cbb_driver);
1207 }
1208 module_exit(tegra234_cbb_exit);
1209
1210 MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234");
This page took 0.102118 seconds and 4 git commands to generate.