1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. 4 */ 5 6 #include <linux/acpi.h> 7 #include <linux/arm-smccc.h> 8 #include <linux/export.h> 9 #include <linux/io.h> 10 #include <linux/kernel.h> 11 #include <linux/mod_devicetable.h> 12 #include <linux/of.h> 13 #include <linux/of_address.h> 14 15 #include <soc/tegra/common.h> 16 #include <soc/tegra/fuse.h> 17 18 #include "fuse.h" 19 20 #define FUSE_SKU_INFO 0x10 21 22 #define ERD_ERR_CONFIG 0x120c 23 #define ERD_MASK_INBAND_ERR 0x1 24 25 #define PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT 4 26 #define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG \ 27 (0xf << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT) 28 #define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT \ 29 (0x3 << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT) 30 31 #define TEGRA_SMCCC_PLATFORM(x) (((x) >> 8) & 0xff) 32 #define TEGRA_SMCCC_CHIP_ID(x) (((x) >> 4) & 0xff) 33 #define TEGRA_SMCCC_MAJOR_REV(x) ((x) & 0xf) 34 #define TEGRA_SMCCC_MINOR_REV(x) ((x) & 0xf) 35 36 static void __iomem *apbmisc_base; 37 static bool long_ram_code; 38 static u32 strapping; 39 static u32 chipid; 40 41 u32 tegra_read_chipid(void) 42 { 43 WARN(!apbmisc_base, "Tegra APB MISC not yet available\n"); 44 45 if (!chipid) 46 chipid = readl_relaxed(apbmisc_base + 4); 47 48 return chipid; 49 } 50 51 u8 tegra_get_chip_id(void) 52 { 53 #if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) 54 s32 soc_id = arm_smccc_get_soc_id_version(); 55 56 if (soc_id >= 0) 57 return TEGRA_SMCCC_CHIP_ID(soc_id); 58 #endif 59 return (tegra_read_chipid() >> 8) & 0xff; 60 } 61 62 u8 tegra_get_major_rev(void) 63 { 64 #if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) 65 s32 soc_id = arm_smccc_get_soc_id_version(); 66 67 if (soc_id >= 0) 68 return TEGRA_SMCCC_MAJOR_REV(soc_id); 69 #endif 70 return (tegra_read_chipid() >> 4) & 0xf; 71 } 72 73 u8 tegra_get_minor_rev(void) 74 { 75 #if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) 76 s32 revision = arm_smccc_get_soc_id_revision(); 77 78 if (revision >= 0) 79 return TEGRA_SMCCC_MINOR_REV(revision); 80 #endif 81 return (tegra_read_chipid() >> 16) & 0xf; 82 83 } 84 85 u8 tegra_get_platform(void) 86 { 87 #if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) 88 s32 revision = arm_smccc_get_soc_id_revision(); 89 90 if (revision >= 0) 91 return TEGRA_SMCCC_PLATFORM(revision); 92 #endif 93 return (tegra_read_chipid() >> 20) & 0xf; 94 } 95 96 bool tegra_is_silicon(void) 97 { 98 switch (tegra_get_chip_id()) { 99 case TEGRA194: 100 case TEGRA234: 101 case TEGRA241: 102 case TEGRA264: 103 if (tegra_get_platform() == 0) 104 return true; 105 106 return false; 107 } 108 109 /* 110 * Chips prior to Tegra194 have a different way of determining whether 111 * they are silicon or not. Since we never supported simulation on the 112 * older Tegra chips, don't bother extracting the information and just 113 * report that we're running on silicon. 114 */ 115 return true; 116 } 117 118 u32 tegra_read_straps(void) 119 { 120 WARN(!chipid, "Tegra ABP MISC not yet available\n"); 121 122 return strapping; 123 } 124 125 u32 tegra_read_ram_code(void) 126 { 127 u32 straps = tegra_read_straps(); 128 129 if (long_ram_code) 130 straps &= PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG; 131 else 132 straps &= PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT; 133 134 return straps >> PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT; 135 } 136 EXPORT_SYMBOL_GPL(tegra_read_ram_code); 137 138 /* 139 * The function sets ERD(Error Response Disable) bit. 140 * This allows to mask inband errors and always send an 141 * OKAY response from CBB to the master which caused error. 142 */ 143 int tegra194_miscreg_mask_serror(void) 144 { 145 if (!apbmisc_base) 146 return -EPROBE_DEFER; 147 148 if (!of_machine_is_compatible("nvidia,tegra194")) { 149 WARN(1, "Only supported for Tegra194 devices!\n"); 150 return -EOPNOTSUPP; 151 } 152 153 writel_relaxed(ERD_MASK_INBAND_ERR, 154 apbmisc_base + ERD_ERR_CONFIG); 155 156 return 0; 157 } 158 EXPORT_SYMBOL(tegra194_miscreg_mask_serror); 159 160 static const struct of_device_id apbmisc_match[] __initconst = { 161 { .compatible = "nvidia,tegra20-apbmisc", }, 162 { .compatible = "nvidia,tegra186-misc", }, 163 { .compatible = "nvidia,tegra194-misc", }, 164 { .compatible = "nvidia,tegra234-misc", }, 165 { .compatible = "nvidia,tegra264-misc", }, 166 {}, 167 }; 168 169 void __init tegra_init_revision(void) 170 { 171 u8 chip_id, minor_rev; 172 173 chip_id = tegra_get_chip_id(); 174 minor_rev = tegra_get_minor_rev(); 175 176 switch (minor_rev) { 177 case 1: 178 tegra_sku_info.revision = TEGRA_REVISION_A01; 179 break; 180 case 2: 181 tegra_sku_info.revision = TEGRA_REVISION_A02; 182 break; 183 case 3: 184 if (chip_id == TEGRA20 && (tegra_fuse_read_spare(18) || 185 tegra_fuse_read_spare(19))) 186 tegra_sku_info.revision = TEGRA_REVISION_A03p; 187 else 188 tegra_sku_info.revision = TEGRA_REVISION_A03; 189 break; 190 case 4: 191 tegra_sku_info.revision = TEGRA_REVISION_A04; 192 break; 193 default: 194 tegra_sku_info.revision = TEGRA_REVISION_UNKNOWN; 195 } 196 197 tegra_sku_info.sku_id = tegra_fuse_read_early(FUSE_SKU_INFO); 198 tegra_sku_info.platform = tegra_get_platform(); 199 } 200 201 static void tegra_init_apbmisc_resources(struct resource *apbmisc, 202 struct resource *straps) 203 { 204 void __iomem *strapping_base; 205 206 apbmisc_base = ioremap(apbmisc->start, resource_size(apbmisc)); 207 if (!apbmisc_base) 208 pr_err("failed to map APBMISC registers\n"); 209 210 strapping_base = ioremap(straps->start, resource_size(straps)); 211 if (strapping_base) { 212 strapping = readl_relaxed(strapping_base); 213 iounmap(strapping_base); 214 } else { 215 pr_err("failed to map strapping options registers\n"); 216 } 217 } 218 219 /** 220 * tegra_init_apbmisc - Initializes Tegra APBMISC and Strapping registers. 221 * 222 * This is called during early init as some of the old 32-bit ARM code needs 223 * information from the APBMISC registers very early during boot. 224 */ 225 void __init tegra_init_apbmisc(void) 226 { 227 struct resource apbmisc, straps; 228 struct device_node *np; 229 230 np = of_find_matching_node(NULL, apbmisc_match); 231 if (!np) { 232 /* 233 * Fall back to legacy initialization for 32-bit ARM only. All 234 * 64-bit ARM device tree files for Tegra are required to have 235 * an APBMISC node. 236 * 237 * This is for backwards-compatibility with old device trees 238 * that didn't contain an APBMISC node. 239 */ 240 if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) { 241 /* APBMISC registers (chip revision, ...) */ 242 apbmisc.start = 0x70000800; 243 apbmisc.end = 0x70000863; 244 apbmisc.flags = IORESOURCE_MEM; 245 246 /* strapping options */ 247 if (of_machine_is_compatible("nvidia,tegra124")) { 248 straps.start = 0x7000e864; 249 straps.end = 0x7000e867; 250 } else { 251 straps.start = 0x70000008; 252 straps.end = 0x7000000b; 253 } 254 255 straps.flags = IORESOURCE_MEM; 256 257 pr_warn("Using APBMISC region %pR\n", &apbmisc); 258 pr_warn("Using strapping options registers %pR\n", 259 &straps); 260 } else { 261 /* 262 * At this point we're not running on Tegra, so play 263 * nice with multi-platform kernels. 264 */ 265 return; 266 } 267 } else { 268 /* 269 * Extract information from the device tree if we've found a 270 * matching node. 271 */ 272 if (of_address_to_resource(np, 0, &apbmisc) < 0) { 273 pr_err("failed to get APBMISC registers\n"); 274 goto put; 275 } 276 277 if (of_address_to_resource(np, 1, &straps) < 0) { 278 pr_err("failed to get strapping options registers\n"); 279 goto put; 280 } 281 } 282 283 tegra_init_apbmisc_resources(&apbmisc, &straps); 284 long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code"); 285 286 put: 287 of_node_put(np); 288 } 289 290 #ifdef CONFIG_ACPI 291 static const struct acpi_device_id apbmisc_acpi_match[] = { 292 { "NVDA2010" }, 293 { /* sentinel */ } 294 }; 295 296 void tegra_acpi_init_apbmisc(void) 297 { 298 struct resource *resources[2] = { NULL }; 299 struct resource_entry *rentry; 300 struct acpi_device *adev = NULL; 301 struct list_head resource_list; 302 int rcount = 0; 303 int ret; 304 305 adev = acpi_dev_get_first_match_dev(apbmisc_acpi_match[0].id, NULL, -1); 306 if (!adev) 307 return; 308 309 INIT_LIST_HEAD(&resource_list); 310 311 ret = acpi_dev_get_memory_resources(adev, &resource_list); 312 if (ret < 0) { 313 pr_err("failed to get APBMISC memory resources"); 314 goto out_put_acpi_dev; 315 } 316 317 /* 318 * Get required memory resources. 319 * 320 * resources[0]: apbmisc. 321 * resources[1]: straps. 322 */ 323 resource_list_for_each_entry(rentry, &resource_list) { 324 if (rcount >= ARRAY_SIZE(resources)) 325 break; 326 327 resources[rcount++] = rentry->res; 328 } 329 330 if (!resources[0]) { 331 pr_err("failed to get APBMISC registers\n"); 332 goto out_free_resource_list; 333 } 334 335 if (!resources[1]) { 336 pr_err("failed to get strapping options registers\n"); 337 goto out_free_resource_list; 338 } 339 340 tegra_init_apbmisc_resources(resources[0], resources[1]); 341 342 out_free_resource_list: 343 acpi_dev_free_resource_list(&resource_list); 344 345 out_put_acpi_dev: 346 acpi_dev_put(adev); 347 } 348 #else 349 void tegra_acpi_init_apbmisc(void) 350 { 351 } 352 #endif 353