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 DEFINE_SHOW_ATTRIBUTE(tegra_cbb_err); 76 77 static int tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb) 78 { 79 static struct dentry *root; 80 81 if (!root) { 82 root = debugfs_create_file("tegra_cbb_err", 0444, NULL, cbb, &tegra_cbb_err_fops); 83 if (IS_ERR_OR_NULL(root)) { 84 pr_err("%s(): could not create debugfs node\n", __func__); 85 return PTR_ERR(root); 86 } 87 } 88 89 return 0; 90 } 91 92 void tegra_cbb_stall_enable(struct tegra_cbb *cbb) 93 { 94 if (cbb->ops->stall_enable) 95 cbb->ops->stall_enable(cbb); 96 } 97 98 void tegra_cbb_fault_enable(struct tegra_cbb *cbb) 99 { 100 if (cbb->ops->fault_enable) 101 cbb->ops->fault_enable(cbb); 102 } 103 104 void tegra_cbb_error_clear(struct tegra_cbb *cbb) 105 { 106 if (cbb->ops->error_clear) 107 cbb->ops->error_clear(cbb); 108 } 109 110 u32 tegra_cbb_get_status(struct tegra_cbb *cbb) 111 { 112 if (cbb->ops->get_status) 113 return cbb->ops->get_status(cbb); 114 115 return 0; 116 } 117 118 int tegra_cbb_get_irq(struct platform_device *pdev, unsigned int *nonsec_irq, 119 unsigned int *sec_irq) 120 { 121 unsigned int index = 0; 122 int num_intr = 0, irq; 123 124 num_intr = platform_irq_count(pdev); 125 if (!num_intr) 126 return -EINVAL; 127 128 if (num_intr == 2) { 129 irq = platform_get_irq(pdev, index); 130 if (irq <= 0) { 131 dev_err(&pdev->dev, "failed to get non-secure IRQ: %d\n", irq); 132 return -ENOENT; 133 } 134 135 *nonsec_irq = irq; 136 index++; 137 } 138 139 irq = platform_get_irq(pdev, index); 140 if (irq <= 0) { 141 dev_err(&pdev->dev, "failed to get secure IRQ: %d\n", irq); 142 return -ENOENT; 143 } 144 145 *sec_irq = irq; 146 147 if (num_intr == 1) 148 dev_dbg(&pdev->dev, "secure IRQ: %u\n", *sec_irq); 149 150 if (num_intr == 2) 151 dev_dbg(&pdev->dev, "secure IRQ: %u, non-secure IRQ: %u\n", *sec_irq, *nonsec_irq); 152 153 return 0; 154 } 155 156 int tegra_cbb_register(struct tegra_cbb *cbb) 157 { 158 int ret; 159 160 if (IS_ENABLED(CONFIG_DEBUG_FS)) { 161 ret = tegra_cbb_err_debugfs_init(cbb); 162 if (ret) { 163 dev_err(cbb->dev, "failed to create debugfs\n"); 164 return ret; 165 } 166 } 167 168 /* register interrupt handler for errors due to different initiators */ 169 ret = cbb->ops->interrupt_enable(cbb); 170 if (ret < 0) { 171 dev_err(cbb->dev, "Failed to register CBB Interrupt ISR"); 172 return ret; 173 } 174 175 cbb->ops->error_enable(cbb); 176 dsb(sy); 177 178 return 0; 179 } 180