linux/drivers/soc/tegra/fuse/fuse-tegra.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify it
   5 * under the terms and conditions of the GNU General Public License,
   6 * version 2, as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope it will be useful, but WITHOUT
   9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  11 * more details.
  12 *
  13 * You should have received a copy of the GNU General Public License
  14 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  15 *
  16 */
  17
  18#include <linux/clk.h>
  19#include <linux/device.h>
  20#include <linux/kobject.h>
  21#include <linux/init.h>
  22#include <linux/io.h>
  23#include <linux/of.h>
  24#include <linux/of_address.h>
  25#include <linux/platform_device.h>
  26#include <linux/slab.h>
  27#include <linux/sys_soc.h>
  28
  29#include <soc/tegra/common.h>
  30#include <soc/tegra/fuse.h>
  31
  32#include "fuse.h"
  33
  34struct tegra_sku_info tegra_sku_info;
  35EXPORT_SYMBOL(tegra_sku_info);
  36
  37static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
  38        [TEGRA_REVISION_UNKNOWN] = "unknown",
  39        [TEGRA_REVISION_A01]     = "A01",
  40        [TEGRA_REVISION_A02]     = "A02",
  41        [TEGRA_REVISION_A03]     = "A03",
  42        [TEGRA_REVISION_A03p]    = "A03 prime",
  43        [TEGRA_REVISION_A04]     = "A04",
  44};
  45
  46static u8 fuse_readb(struct tegra_fuse *fuse, unsigned int offset)
  47{
  48        u32 val;
  49
  50        val = fuse->read(fuse, round_down(offset, 4));
  51        val >>= (offset % 4) * 8;
  52        val &= 0xff;
  53
  54        return val;
  55}
  56
  57static ssize_t fuse_read(struct file *fd, struct kobject *kobj,
  58                         struct bin_attribute *attr, char *buf,
  59                         loff_t pos, size_t size)
  60{
  61        struct device *dev = kobj_to_dev(kobj);
  62        struct tegra_fuse *fuse = dev_get_drvdata(dev);
  63        int i;
  64
  65        if (pos < 0 || pos >= attr->size)
  66                return 0;
  67
  68        if (size > attr->size - pos)
  69                size = attr->size - pos;
  70
  71        for (i = 0; i < size; i++)
  72                buf[i] = fuse_readb(fuse, pos + i);
  73
  74        return i;
  75}
  76
  77static struct bin_attribute fuse_bin_attr = {
  78        .attr = { .name = "fuse", .mode = S_IRUGO, },
  79        .read = fuse_read,
  80};
  81
  82static int tegra_fuse_create_sysfs(struct device *dev, unsigned int size,
  83                                   const struct tegra_fuse_info *info)
  84{
  85        fuse_bin_attr.size = size;
  86
  87        return device_create_bin_file(dev, &fuse_bin_attr);
  88}
  89
  90static const struct of_device_id car_match[] __initconst = {
  91        { .compatible = "nvidia,tegra20-car", },
  92        { .compatible = "nvidia,tegra30-car", },
  93        { .compatible = "nvidia,tegra114-car", },
  94        { .compatible = "nvidia,tegra124-car", },
  95        { .compatible = "nvidia,tegra132-car", },
  96        { .compatible = "nvidia,tegra210-car", },
  97        {},
  98};
  99
 100static struct tegra_fuse *fuse = &(struct tegra_fuse) {
 101        .base = NULL,
 102        .soc = NULL,
 103};
 104
 105static const struct of_device_id tegra_fuse_match[] = {
 106#ifdef CONFIG_ARCH_TEGRA_186_SOC
 107        { .compatible = "nvidia,tegra186-efuse", .data = &tegra186_fuse_soc },
 108#endif
 109#ifdef CONFIG_ARCH_TEGRA_210_SOC
 110        { .compatible = "nvidia,tegra210-efuse", .data = &tegra210_fuse_soc },
 111#endif
 112#ifdef CONFIG_ARCH_TEGRA_132_SOC
 113        { .compatible = "nvidia,tegra132-efuse", .data = &tegra124_fuse_soc },
 114#endif
 115#ifdef CONFIG_ARCH_TEGRA_124_SOC
 116        { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_fuse_soc },
 117#endif
 118#ifdef CONFIG_ARCH_TEGRA_114_SOC
 119        { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_fuse_soc },
 120#endif
 121#ifdef CONFIG_ARCH_TEGRA_3x_SOC
 122        { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_fuse_soc },
 123#endif
 124#ifdef CONFIG_ARCH_TEGRA_2x_SOC
 125        { .compatible = "nvidia,tegra20-efuse", .data = &tegra20_fuse_soc },
 126#endif
 127        { /* sentinel */ }
 128};
 129
 130static int tegra_fuse_probe(struct platform_device *pdev)
 131{
 132        void __iomem *base = fuse->base;
 133        struct resource *res;
 134        int err;
 135
 136        /* take over the memory region from the early initialization */
 137        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 138        fuse->phys = res->start;
 139        fuse->base = devm_ioremap_resource(&pdev->dev, res);
 140        if (IS_ERR(fuse->base))
 141                return PTR_ERR(fuse->base);
 142
 143        fuse->clk = devm_clk_get(&pdev->dev, "fuse");
 144        if (IS_ERR(fuse->clk)) {
 145                dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
 146                        PTR_ERR(fuse->clk));
 147                return PTR_ERR(fuse->clk);
 148        }
 149
 150        platform_set_drvdata(pdev, fuse);
 151        fuse->dev = &pdev->dev;
 152
 153        if (fuse->soc->probe) {
 154                err = fuse->soc->probe(fuse);
 155                if (err < 0)
 156                        return err;
 157        }
 158
 159        if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,
 160                                    fuse->soc->info))
 161                return -ENODEV;
 162
 163        /* release the early I/O memory mapping */
 164        iounmap(base);
 165
 166        return 0;
 167}
 168
 169static struct platform_driver tegra_fuse_driver = {
 170        .driver = {
 171                .name = "tegra-fuse",
 172                .of_match_table = tegra_fuse_match,
 173                .suppress_bind_attrs = true,
 174        },
 175        .probe = tegra_fuse_probe,
 176};
 177builtin_platform_driver(tegra_fuse_driver);
 178
 179bool __init tegra_fuse_read_spare(unsigned int spare)
 180{
 181        unsigned int offset = fuse->soc->info->spare + spare * 4;
 182
 183        return fuse->read_early(fuse, offset) & 1;
 184}
 185
 186u32 __init tegra_fuse_read_early(unsigned int offset)
 187{
 188        return fuse->read_early(fuse, offset);
 189}
 190
 191int tegra_fuse_readl(unsigned long offset, u32 *value)
 192{
 193        if (!fuse->read)
 194                return -EPROBE_DEFER;
 195
 196        *value = fuse->read(fuse, offset);
 197
 198        return 0;
 199}
 200EXPORT_SYMBOL(tegra_fuse_readl);
 201
 202static void tegra_enable_fuse_clk(void __iomem *base)
 203{
 204        u32 reg;
 205
 206        reg = readl_relaxed(base + 0x48);
 207        reg |= 1 << 28;
 208        writel(reg, base + 0x48);
 209
 210        /*
 211         * Enable FUSE clock. This needs to be hardcoded because the clock
 212         * subsystem is not active during early boot.
 213         */
 214        reg = readl(base + 0x14);
 215        reg |= 1 << 7;
 216        writel(reg, base + 0x14);
 217}
 218
 219struct device * __init tegra_soc_device_register(void)
 220{
 221        struct soc_device_attribute *attr;
 222        struct soc_device *dev;
 223
 224        attr = kzalloc(sizeof(*attr), GFP_KERNEL);
 225        if (!attr)
 226                return NULL;
 227
 228        attr->family = kasprintf(GFP_KERNEL, "Tegra");
 229        attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_sku_info.revision);
 230        attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id());
 231
 232        dev = soc_device_register(attr);
 233        if (IS_ERR(dev)) {
 234                kfree(attr->soc_id);
 235                kfree(attr->revision);
 236                kfree(attr->family);
 237                kfree(attr);
 238                return ERR_CAST(dev);
 239        }
 240
 241        return soc_device_to_device(dev);
 242}
 243
 244static int __init tegra_init_fuse(void)
 245{
 246        const struct of_device_id *match;
 247        struct device_node *np;
 248        struct resource regs;
 249
 250        tegra_init_apbmisc();
 251
 252        np = of_find_matching_node_and_match(NULL, tegra_fuse_match, &match);
 253        if (!np) {
 254                /*
 255                 * Fall back to legacy initialization for 32-bit ARM only. All
 256                 * 64-bit ARM device tree files for Tegra are required to have
 257                 * a FUSE node.
 258                 *
 259                 * This is for backwards-compatibility with old device trees
 260                 * that didn't contain a FUSE node.
 261                 */
 262                if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) {
 263                        u8 chip = tegra_get_chip_id();
 264
 265                        regs.start = 0x7000f800;
 266                        regs.end = 0x7000fbff;
 267                        regs.flags = IORESOURCE_MEM;
 268
 269                        switch (chip) {
 270#ifdef CONFIG_ARCH_TEGRA_2x_SOC
 271                        case TEGRA20:
 272                                fuse->soc = &tegra20_fuse_soc;
 273                                break;
 274#endif
 275
 276#ifdef CONFIG_ARCH_TEGRA_3x_SOC
 277                        case TEGRA30:
 278                                fuse->soc = &tegra30_fuse_soc;
 279                                break;
 280#endif
 281
 282#ifdef CONFIG_ARCH_TEGRA_114_SOC
 283                        case TEGRA114:
 284                                fuse->soc = &tegra114_fuse_soc;
 285                                break;
 286#endif
 287
 288#ifdef CONFIG_ARCH_TEGRA_124_SOC
 289                        case TEGRA124:
 290                                fuse->soc = &tegra124_fuse_soc;
 291                                break;
 292#endif
 293
 294                        default:
 295                                pr_warn("Unsupported SoC: %02x\n", chip);
 296                                break;
 297                        }
 298                } else {
 299                        /*
 300                         * At this point we're not running on Tegra, so play
 301                         * nice with multi-platform kernels.
 302                         */
 303                        return 0;
 304                }
 305        } else {
 306                /*
 307                 * Extract information from the device tree if we've found a
 308                 * matching node.
 309                 */
 310                if (of_address_to_resource(np, 0, &regs) < 0) {
 311                        pr_err("failed to get FUSE register\n");
 312                        return -ENXIO;
 313                }
 314
 315                fuse->soc = match->data;
 316        }
 317
 318        np = of_find_matching_node(NULL, car_match);
 319        if (np) {
 320                void __iomem *base = of_iomap(np, 0);
 321                if (base) {
 322                        tegra_enable_fuse_clk(base);
 323                        iounmap(base);
 324                } else {
 325                        pr_err("failed to map clock registers\n");
 326                        return -ENXIO;
 327                }
 328        }
 329
 330        fuse->base = ioremap_nocache(regs.start, resource_size(&regs));
 331        if (!fuse->base) {
 332                pr_err("failed to map FUSE registers\n");
 333                return -ENXIO;
 334        }
 335
 336        fuse->soc->init(fuse);
 337
 338        pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n",
 339                tegra_revision_name[tegra_sku_info.revision],
 340                tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id,
 341                tegra_sku_info.soc_process_id);
 342        pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
 343                 tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
 344
 345
 346        return 0;
 347}
 348early_initcall(tegra_init_fuse);
 349
 350#ifdef CONFIG_ARM64
 351static int __init tegra_init_soc(void)
 352{
 353        struct device_node *np;
 354        struct device *soc;
 355
 356        /* make sure we're running on Tegra */
 357        np = of_find_matching_node(NULL, tegra_fuse_match);
 358        if (!np)
 359                return 0;
 360
 361        of_node_put(np);
 362
 363        soc = tegra_soc_device_register();
 364        if (IS_ERR(soc)) {
 365                pr_err("failed to register SoC device: %ld\n", PTR_ERR(soc));
 366                return PTR_ERR(soc);
 367        }
 368
 369        return 0;
 370}
 371device_initcall(tegra_init_soc);
 372#endif
 373