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