1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved |
4 | */ |
5 | |
6 | #include <linux/clk.h> |
7 | #include <linux/cpufeature.h> |
8 | #include <linux/debugfs.h> |
9 | #include <linux/module.h> |
10 | #include <linux/platform_device.h> |
11 | #include <linux/device.h> |
12 | #include <linux/io.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/ioport.h> |
15 | #include <soc/tegra/fuse.h> |
16 | #include <soc/tegra/tegra-cbb.h> |
17 | |
18 | void tegra_cbb_print_err(struct seq_file *file, const char *fmt, ...) |
19 | { |
20 | struct va_format vaf; |
21 | va_list args; |
22 | |
23 | va_start(args, fmt); |
24 | |
25 | if (file) { |
26 | seq_vprintf(m: file, fmt, args); |
27 | } else { |
28 | vaf.fmt = fmt; |
29 | vaf.va = &args; |
30 | pr_crit("%pV" , &vaf); |
31 | } |
32 | |
33 | va_end(args); |
34 | } |
35 | |
36 | void tegra_cbb_print_cache(struct seq_file *file, u32 cache) |
37 | { |
38 | const char *buff_str, *mod_str, *rd_str, *wr_str; |
39 | |
40 | buff_str = (cache & BIT(0)) ? "Bufferable " : "" ; |
41 | mod_str = (cache & BIT(1)) ? "Modifiable " : "" ; |
42 | rd_str = (cache & BIT(2)) ? "Read-Allocate " : "" ; |
43 | wr_str = (cache & BIT(3)) ? "Write-Allocate" : "" ; |
44 | |
45 | if (cache == 0x0) |
46 | buff_str = "Device Non-Bufferable" ; |
47 | |
48 | tegra_cbb_print_err(file, fmt: "\t Cache\t\t\t: 0x%x -- %s%s%s%s\n" , |
49 | cache, buff_str, mod_str, rd_str, wr_str); |
50 | } |
51 | |
52 | void tegra_cbb_print_prot(struct seq_file *file, u32 prot) |
53 | { |
54 | const char *data_str, *secure_str, *priv_str; |
55 | |
56 | data_str = (prot & 0x4) ? "Instruction" : "Data" ; |
57 | secure_str = (prot & 0x2) ? "Non-Secure" : "Secure" ; |
58 | priv_str = (prot & 0x1) ? "Privileged" : "Unprivileged" ; |
59 | |
60 | tegra_cbb_print_err(file, fmt: "\t Protection\t\t: 0x%x -- %s, %s, %s Access\n" , |
61 | prot, priv_str, secure_str, data_str); |
62 | } |
63 | |
64 | static int tegra_cbb_err_show(struct seq_file *file, void *data) |
65 | { |
66 | struct tegra_cbb *cbb = file->private; |
67 | |
68 | return cbb->ops->debugfs_show(cbb, file, data); |
69 | } |
70 | DEFINE_SHOW_ATTRIBUTE(tegra_cbb_err); |
71 | |
72 | static int tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb) |
73 | { |
74 | static struct dentry *root; |
75 | |
76 | if (!root) { |
77 | root = debugfs_create_file(name: "tegra_cbb_err" , mode: 0444, NULL, data: cbb, fops: &tegra_cbb_err_fops); |
78 | if (IS_ERR_OR_NULL(ptr: root)) { |
79 | pr_err("%s(): could not create debugfs node\n" , __func__); |
80 | return PTR_ERR(ptr: root); |
81 | } |
82 | } |
83 | |
84 | return 0; |
85 | } |
86 | |
87 | void tegra_cbb_stall_enable(struct tegra_cbb *cbb) |
88 | { |
89 | if (cbb->ops->stall_enable) |
90 | cbb->ops->stall_enable(cbb); |
91 | } |
92 | |
93 | void tegra_cbb_fault_enable(struct tegra_cbb *cbb) |
94 | { |
95 | if (cbb->ops->fault_enable) |
96 | cbb->ops->fault_enable(cbb); |
97 | } |
98 | |
99 | void tegra_cbb_error_clear(struct tegra_cbb *cbb) |
100 | { |
101 | if (cbb->ops->error_clear) |
102 | cbb->ops->error_clear(cbb); |
103 | } |
104 | |
105 | u32 tegra_cbb_get_status(struct tegra_cbb *cbb) |
106 | { |
107 | if (cbb->ops->get_status) |
108 | return cbb->ops->get_status(cbb); |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | int tegra_cbb_get_irq(struct platform_device *pdev, unsigned int *nonsec_irq, |
114 | unsigned int *sec_irq) |
115 | { |
116 | unsigned int index = 0; |
117 | int num_intr = 0, irq; |
118 | |
119 | num_intr = platform_irq_count(pdev); |
120 | if (!num_intr) |
121 | return -EINVAL; |
122 | |
123 | if (num_intr == 2) { |
124 | irq = platform_get_irq(pdev, index); |
125 | if (irq <= 0) |
126 | return -ENOENT; |
127 | |
128 | *nonsec_irq = irq; |
129 | index++; |
130 | } |
131 | |
132 | irq = platform_get_irq(pdev, index); |
133 | if (irq <= 0) |
134 | return -ENOENT; |
135 | |
136 | *sec_irq = irq; |
137 | |
138 | if (num_intr == 1) |
139 | dev_dbg(&pdev->dev, "secure IRQ: %u\n" , *sec_irq); |
140 | |
141 | if (num_intr == 2) |
142 | dev_dbg(&pdev->dev, "secure IRQ: %u, non-secure IRQ: %u\n" , *sec_irq, *nonsec_irq); |
143 | |
144 | return 0; |
145 | } |
146 | |
147 | int tegra_cbb_register(struct tegra_cbb *cbb) |
148 | { |
149 | int ret; |
150 | |
151 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
152 | ret = tegra_cbb_err_debugfs_init(cbb); |
153 | if (ret) { |
154 | dev_err(cbb->dev, "failed to create debugfs\n" ); |
155 | return ret; |
156 | } |
157 | } |
158 | |
159 | /* register interrupt handler for errors due to different initiators */ |
160 | ret = cbb->ops->interrupt_enable(cbb); |
161 | if (ret < 0) { |
162 | dev_err(cbb->dev, "Failed to register CBB Interrupt ISR" ); |
163 | return ret; |
164 | } |
165 | |
166 | cbb->ops->error_enable(cbb); |
167 | dsb(sy); |
168 | |
169 | return 0; |
170 | } |
171 | |