linux/drivers/soc/tegra/fuse/speedo-tegra210.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013-2015, 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#include <linux/device.h>
  18#include <linux/kernel.h>
  19#include <linux/bug.h>
  20
  21#include <soc/tegra/fuse.h>
  22
  23#include "fuse.h"
  24
  25#define CPU_PROCESS_CORNERS     2
  26#define GPU_PROCESS_CORNERS     2
  27#define SOC_PROCESS_CORNERS     3
  28
  29#define FUSE_CPU_SPEEDO_0       0x014
  30#define FUSE_CPU_SPEEDO_1       0x02c
  31#define FUSE_CPU_SPEEDO_2       0x030
  32#define FUSE_SOC_SPEEDO_0       0x034
  33#define FUSE_SOC_SPEEDO_1       0x038
  34#define FUSE_SOC_SPEEDO_2       0x03c
  35#define FUSE_CPU_IDDQ           0x018
  36#define FUSE_SOC_IDDQ           0x040
  37#define FUSE_GPU_IDDQ           0x128
  38#define FUSE_FT_REV             0x028
  39
  40enum {
  41        THRESHOLD_INDEX_0,
  42        THRESHOLD_INDEX_1,
  43        THRESHOLD_INDEX_COUNT,
  44};
  45
  46static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
  47        { 2119, UINT_MAX },
  48        { 2119, UINT_MAX },
  49};
  50
  51static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = {
  52        { UINT_MAX, UINT_MAX },
  53        { UINT_MAX, UINT_MAX },
  54};
  55
  56static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = {
  57        { 1950, 2100, UINT_MAX },
  58        { 1950, 2100, UINT_MAX },
  59};
  60
  61static u8 __init get_speedo_revision(void)
  62{
  63        return tegra_fuse_read_spare(4) << 2 |
  64               tegra_fuse_read_spare(3) << 1 |
  65               tegra_fuse_read_spare(2) << 0;
  66}
  67
  68static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
  69                                         u8 speedo_rev, int *threshold)
  70{
  71        int sku = sku_info->sku_id;
  72
  73        /* Assign to default */
  74        sku_info->cpu_speedo_id = 0;
  75        sku_info->soc_speedo_id = 0;
  76        sku_info->gpu_speedo_id = 0;
  77        *threshold = THRESHOLD_INDEX_0;
  78
  79        switch (sku) {
  80        case 0x00: /* Engineering SKU */
  81        case 0x01: /* Engineering SKU */
  82        case 0x07:
  83        case 0x17:
  84        case 0x27:
  85                if (speedo_rev >= 2)
  86                        sku_info->gpu_speedo_id = 1;
  87                break;
  88
  89        case 0x13:
  90                if (speedo_rev >= 2)
  91                        sku_info->gpu_speedo_id = 1;
  92
  93                sku_info->cpu_speedo_id = 1;
  94                break;
  95
  96        default:
  97                pr_err("Tegra210: unknown SKU %#04x\n", sku);
  98                /* Using the default for the error case */
  99                break;
 100        }
 101}
 102
 103static int get_process_id(int value, const u32 *speedos, unsigned int num)
 104{
 105        unsigned int i;
 106
 107        for (i = 0; i < num; i++)
 108                if (value < speedos[num])
 109                        return i;
 110
 111        return -EINVAL;
 112}
 113
 114void __init tegra210_init_speedo_data(struct tegra_sku_info *sku_info)
 115{
 116        int cpu_speedo[3], soc_speedo[3], cpu_iddq, gpu_iddq, soc_iddq;
 117        unsigned int index;
 118        u8 speedo_revision;
 119
 120        BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
 121                        THRESHOLD_INDEX_COUNT);
 122        BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) !=
 123                        THRESHOLD_INDEX_COUNT);
 124        BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) !=
 125                        THRESHOLD_INDEX_COUNT);
 126
 127        /* Read speedo/IDDQ fuses */
 128        cpu_speedo[0] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_0);
 129        cpu_speedo[1] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_1);
 130        cpu_speedo[2] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2);
 131
 132        soc_speedo[0] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_0);
 133        soc_speedo[1] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_1);
 134        soc_speedo[2] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2);
 135
 136        cpu_iddq = tegra_fuse_read_early(FUSE_CPU_IDDQ) * 4;
 137        soc_iddq = tegra_fuse_read_early(FUSE_SOC_IDDQ) * 4;
 138        gpu_iddq = tegra_fuse_read_early(FUSE_GPU_IDDQ) * 5;
 139
 140        /*
 141         * Determine CPU, GPU and SoC speedo values depending on speedo fusing
 142         * revision. Note that GPU speedo value is fused in CPU_SPEEDO_2.
 143         */
 144        speedo_revision = get_speedo_revision();
 145        pr_info("Speedo Revision %u\n", speedo_revision);
 146
 147        if (speedo_revision >= 3) {
 148                sku_info->cpu_speedo_value = cpu_speedo[0];
 149                sku_info->gpu_speedo_value = cpu_speedo[2];
 150                sku_info->soc_speedo_value = soc_speedo[0];
 151        } else if (speedo_revision == 2) {
 152                sku_info->cpu_speedo_value = (-1938 + (1095 * cpu_speedo[0] / 100)) / 10;
 153                sku_info->gpu_speedo_value = (-1662 + (1082 * cpu_speedo[2] / 100)) / 10;
 154                sku_info->soc_speedo_value = ( -705 + (1037 * soc_speedo[0] / 100)) / 10;
 155        } else {
 156                sku_info->cpu_speedo_value = 2100;
 157                sku_info->gpu_speedo_value = cpu_speedo[2] - 75;
 158                sku_info->soc_speedo_value = 1900;
 159        }
 160
 161        if ((sku_info->cpu_speedo_value <= 0) ||
 162            (sku_info->gpu_speedo_value <= 0) ||
 163            (sku_info->soc_speedo_value <= 0)) {
 164                WARN(1, "speedo value not fused\n");
 165                return;
 166        }
 167
 168        rev_sku_to_speedo_ids(sku_info, speedo_revision, &index);
 169
 170        sku_info->gpu_process_id = get_process_id(sku_info->gpu_speedo_value,
 171                                                  gpu_process_speedos[index],
 172                                                  GPU_PROCESS_CORNERS);
 173
 174        sku_info->cpu_process_id = get_process_id(sku_info->cpu_speedo_value,
 175                                                  cpu_process_speedos[index],
 176                                                  CPU_PROCESS_CORNERS);
 177
 178        sku_info->soc_process_id = get_process_id(sku_info->soc_speedo_value,
 179                                                  soc_process_speedos[index],
 180                                                  SOC_PROCESS_CORNERS);
 181
 182        pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n",
 183                 sku_info->gpu_speedo_id, sku_info->gpu_speedo_value);
 184}
 185