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