linux/drivers/soc/tegra/fuse/tegra-apbmisc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/of.h>
   8#include <linux/of_address.h>
   9#include <linux/io.h>
  10
  11#include <soc/tegra/fuse.h>
  12#include <soc/tegra/common.h>
  13
  14#include "fuse.h"
  15
  16#define FUSE_SKU_INFO   0x10
  17
  18#define PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT      4
  19#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG  \
  20        (0xf << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
  21#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT \
  22        (0x3 << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
  23
  24static void __iomem *apbmisc_base;
  25static void __iomem *strapping_base;
  26static bool long_ram_code;
  27
  28u32 tegra_read_chipid(void)
  29{
  30        if (!apbmisc_base) {
  31                WARN(1, "Tegra Chip ID not yet available\n");
  32                return 0;
  33        }
  34
  35        return readl_relaxed(apbmisc_base + 4);
  36}
  37
  38u8 tegra_get_chip_id(void)
  39{
  40        return (tegra_read_chipid() >> 8) & 0xff;
  41}
  42
  43u32 tegra_read_straps(void)
  44{
  45        if (strapping_base)
  46                return readl_relaxed(strapping_base);
  47        else
  48                return 0;
  49}
  50
  51u32 tegra_read_ram_code(void)
  52{
  53        u32 straps = tegra_read_straps();
  54
  55        if (long_ram_code)
  56                straps &= PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG;
  57        else
  58                straps &= PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT;
  59
  60        return straps >> PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT;
  61}
  62
  63static const struct of_device_id apbmisc_match[] __initconst = {
  64        { .compatible = "nvidia,tegra20-apbmisc", },
  65        { .compatible = "nvidia,tegra186-misc", },
  66        {},
  67};
  68
  69void __init tegra_init_revision(void)
  70{
  71        u32 id, chip_id, minor_rev;
  72        int rev;
  73
  74        id = tegra_read_chipid();
  75        chip_id = (id >> 8) & 0xff;
  76        minor_rev = (id >> 16) & 0xf;
  77
  78        switch (minor_rev) {
  79        case 1:
  80                rev = TEGRA_REVISION_A01;
  81                break;
  82        case 2:
  83                rev = TEGRA_REVISION_A02;
  84                break;
  85        case 3:
  86                if (chip_id == TEGRA20 && (tegra_fuse_read_spare(18) ||
  87                                           tegra_fuse_read_spare(19)))
  88                        rev = TEGRA_REVISION_A03p;
  89                else
  90                        rev = TEGRA_REVISION_A03;
  91                break;
  92        case 4:
  93                rev = TEGRA_REVISION_A04;
  94                break;
  95        default:
  96                rev = TEGRA_REVISION_UNKNOWN;
  97        }
  98
  99        tegra_sku_info.revision = rev;
 100
 101        tegra_sku_info.sku_id = tegra_fuse_read_early(FUSE_SKU_INFO);
 102}
 103
 104void __init tegra_init_apbmisc(void)
 105{
 106        struct resource apbmisc, straps;
 107        struct device_node *np;
 108
 109        np = of_find_matching_node(NULL, apbmisc_match);
 110        if (!np) {
 111                /*
 112                 * Fall back to legacy initialization for 32-bit ARM only. All
 113                 * 64-bit ARM device tree files for Tegra are required to have
 114                 * an APBMISC node.
 115                 *
 116                 * This is for backwards-compatibility with old device trees
 117                 * that didn't contain an APBMISC node.
 118                 */
 119                if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) {
 120                        /* APBMISC registers (chip revision, ...) */
 121                        apbmisc.start = 0x70000800;
 122                        apbmisc.end = 0x70000863;
 123                        apbmisc.flags = IORESOURCE_MEM;
 124
 125                        /* strapping options */
 126                        if (tegra_get_chip_id() == TEGRA124) {
 127                                straps.start = 0x7000e864;
 128                                straps.end = 0x7000e867;
 129                        } else {
 130                                straps.start = 0x70000008;
 131                                straps.end = 0x7000000b;
 132                        }
 133
 134                        straps.flags = IORESOURCE_MEM;
 135
 136                        pr_warn("Using APBMISC region %pR\n", &apbmisc);
 137                        pr_warn("Using strapping options registers %pR\n",
 138                                &straps);
 139                } else {
 140                        /*
 141                         * At this point we're not running on Tegra, so play
 142                         * nice with multi-platform kernels.
 143                         */
 144                        return;
 145                }
 146        } else {
 147                /*
 148                 * Extract information from the device tree if we've found a
 149                 * matching node.
 150                 */
 151                if (of_address_to_resource(np, 0, &apbmisc) < 0) {
 152                        pr_err("failed to get APBMISC registers\n");
 153                        return;
 154                }
 155
 156                if (of_address_to_resource(np, 1, &straps) < 0) {
 157                        pr_err("failed to get strapping options registers\n");
 158                        return;
 159                }
 160        }
 161
 162        apbmisc_base = ioremap_nocache(apbmisc.start, resource_size(&apbmisc));
 163        if (!apbmisc_base)
 164                pr_err("failed to map APBMISC registers\n");
 165
 166        strapping_base = ioremap_nocache(straps.start, resource_size(&straps));
 167        if (!strapping_base)
 168                pr_err("failed to map strapping options registers\n");
 169
 170        long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code");
 171}
 172