1ef2ee5d0SMichal Meloun /*- 2ef2ee5d0SMichal Meloun * Copyright (c) 2015 Michal Meloun 3ef2ee5d0SMichal Meloun * All rights reserved. 4ef2ee5d0SMichal Meloun * 5ef2ee5d0SMichal Meloun * Redistribution and use in source and binary forms, with or without 6ef2ee5d0SMichal Meloun * modification, are permitted provided that the following conditions 7ef2ee5d0SMichal Meloun * are met: 8ef2ee5d0SMichal Meloun * 1. Redistributions of source code must retain the above copyright 9ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer. 10ef2ee5d0SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 11ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer in the 12ef2ee5d0SMichal Meloun * documentation and/or other materials provided with the distribution. 13ef2ee5d0SMichal Meloun * 14ef2ee5d0SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ef2ee5d0SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ef2ee5d0SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ef2ee5d0SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ef2ee5d0SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ef2ee5d0SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ef2ee5d0SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ef2ee5d0SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ef2ee5d0SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ef2ee5d0SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ef2ee5d0SMichal Meloun * SUCH DAMAGE. 25ef2ee5d0SMichal Meloun */ 26ef2ee5d0SMichal Meloun 27ef2ee5d0SMichal Meloun #include <sys/param.h> 28ef2ee5d0SMichal Meloun #include <sys/systm.h> 29ef2ee5d0SMichal Meloun #include <sys/bus.h> 30ef2ee5d0SMichal Meloun #include <sys/clock.h> 31ef2ee5d0SMichal Meloun #include <sys/kernel.h> 32ef2ee5d0SMichal Meloun #include <sys/limits.h> 33ef2ee5d0SMichal Meloun #include <sys/lock.h> 34ef2ee5d0SMichal Meloun #include <sys/mutex.h> 35ef2ee5d0SMichal Meloun #include <sys/module.h> 36ef2ee5d0SMichal Meloun #include <sys/resource.h> 37ef2ee5d0SMichal Meloun #include <sys/rman.h> 38ef2ee5d0SMichal Meloun 39ef2ee5d0SMichal Meloun #include <machine/bus.h> 40ef2ee5d0SMichal Meloun #include <machine/resource.h> 41ef2ee5d0SMichal Meloun 42be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 431f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h> 44ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h> 45ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 46ef2ee5d0SMichal Meloun 47ef2ee5d0SMichal Meloun #include <arm/nvidia/tegra_efuse.h> 48ef2ee5d0SMichal Meloun 49b9cbd68dSMichal Meloun #define FUSES_START 0x100 50b9cbd68dSMichal Meloun #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (FUSES_START + (_r))) 51ef2ee5d0SMichal Meloun 52b9cbd68dSMichal Meloun struct efuse_soc; 53ef2ee5d0SMichal Meloun struct tegra_efuse_softc { 54ef2ee5d0SMichal Meloun device_t dev; 55ef2ee5d0SMichal Meloun struct resource *mem_res; 56ef2ee5d0SMichal Meloun 57b9cbd68dSMichal Meloun struct efuse_soc *soc; 58ef2ee5d0SMichal Meloun clk_t clk; 59ef2ee5d0SMichal Meloun hwreset_t reset; 60ef2ee5d0SMichal Meloun }; 61ef2ee5d0SMichal Meloun 62b9cbd68dSMichal Meloun struct tegra_efuse_softc *dev_sc; 63ef2ee5d0SMichal Meloun struct tegra_sku_info tegra_sku_info; 64ef2ee5d0SMichal Meloun static char *tegra_rev_name[] = { 65ef2ee5d0SMichal Meloun [TEGRA_REVISION_UNKNOWN] = "unknown", 66ef2ee5d0SMichal Meloun [TEGRA_REVISION_A01] = "A01", 67ef2ee5d0SMichal Meloun [TEGRA_REVISION_A02] = "A02", 68ef2ee5d0SMichal Meloun [TEGRA_REVISION_A03] = "A03", 69ef2ee5d0SMichal Meloun [TEGRA_REVISION_A03p] = "A03 prime", 70ef2ee5d0SMichal Meloun [TEGRA_REVISION_A04] = "A04", 71ef2ee5d0SMichal Meloun }; 72ef2ee5d0SMichal Meloun 73b9cbd68dSMichal Meloun struct efuse_soc { 74b9cbd68dSMichal Meloun void (*init)(struct tegra_efuse_softc *sc, 75b9cbd68dSMichal Meloun struct tegra_sku_info *sku); 76b9cbd68dSMichal Meloun }; 77b9cbd68dSMichal Meloun 78b9cbd68dSMichal Meloun static void tegra124_init(struct tegra_efuse_softc *sc, 79b9cbd68dSMichal Meloun struct tegra_sku_info *sku); 80b9cbd68dSMichal Meloun struct efuse_soc tegra124_efuse_soc = { 81b9cbd68dSMichal Meloun .init = tegra124_init, 82b9cbd68dSMichal Meloun }; 83b9cbd68dSMichal Meloun 84b9cbd68dSMichal Meloun static void tegra210_init(struct tegra_efuse_softc *sc, 85b9cbd68dSMichal Meloun struct tegra_sku_info *sku); 86b9cbd68dSMichal Meloun struct efuse_soc tegra210_efuse_soc = { 87b9cbd68dSMichal Meloun .init = tegra210_init, 88b9cbd68dSMichal Meloun }; 89b9cbd68dSMichal Meloun 90b9cbd68dSMichal Meloun static struct ofw_compat_data compat_data[] = { 91b9cbd68dSMichal Meloun {"nvidia,tegra124-efuse", (intptr_t)&tegra124_efuse_soc}, 92b9cbd68dSMichal Meloun {"nvidia,tegra210-efuse", (intptr_t)&tegra210_efuse_soc}, 93b9cbd68dSMichal Meloun {NULL, 0} 94b9cbd68dSMichal Meloun }; 95ef2ee5d0SMichal Meloun 96ef2ee5d0SMichal Meloun /* ---------------------- Tegra 124 specific code & data --------------- */ 97ef2ee5d0SMichal Meloun #define TEGRA124_CPU_PROCESS_CORNERS 2 98ef2ee5d0SMichal Meloun #define TEGRA124_GPU_PROCESS_CORNERS 2 99ef2ee5d0SMichal Meloun #define TEGRA124_SOC_PROCESS_CORNERS 2 100ef2ee5d0SMichal Meloun 101ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_SKU_INFO 0x10 102ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_CPU_SPEEDO_0 0x14 103ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_CPU_IDDQ 0x18 104ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_FT_REV 0x28 105ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_CPU_SPEEDO_1 0x2c 106ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_CPU_SPEEDO_2 0x30 107ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_SOC_SPEEDO_0 0x34 108ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_SOC_SPEEDO_1 0x38 109ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_SOC_SPEEDO_2 0x3c 110ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_SOC_IDDQ 0x40 111ef2ee5d0SMichal Meloun #define TEGRA124_FUSE_GPU_IDDQ 0x128 112ef2ee5d0SMichal Meloun 113ef2ee5d0SMichal Meloun enum { 114ef2ee5d0SMichal Meloun TEGRA124_THRESHOLD_INDEX_0, 115ef2ee5d0SMichal Meloun TEGRA124_THRESHOLD_INDEX_1, 116ef2ee5d0SMichal Meloun TEGRA124_THRESHOLD_INDEX_COUNT, 117ef2ee5d0SMichal Meloun }; 118ef2ee5d0SMichal Meloun 119ef2ee5d0SMichal Meloun static uint32_t tegra124_cpu_process_speedos[][TEGRA124_CPU_PROCESS_CORNERS] = 120ef2ee5d0SMichal Meloun { 121ef2ee5d0SMichal Meloun {2190, UINT_MAX}, 122ef2ee5d0SMichal Meloun {0, UINT_MAX}, 123ef2ee5d0SMichal Meloun }; 124ef2ee5d0SMichal Meloun 125ef2ee5d0SMichal Meloun static uint32_t tegra124_gpu_process_speedos[][TEGRA124_GPU_PROCESS_CORNERS] = 126ef2ee5d0SMichal Meloun { 127ef2ee5d0SMichal Meloun {1965, UINT_MAX}, 128ef2ee5d0SMichal Meloun {0, UINT_MAX}, 129ef2ee5d0SMichal Meloun }; 130ef2ee5d0SMichal Meloun 131ef2ee5d0SMichal Meloun static uint32_t tegra124_soc_process_speedos[][TEGRA124_SOC_PROCESS_CORNERS] = 132ef2ee5d0SMichal Meloun { 133ef2ee5d0SMichal Meloun {2101, UINT_MAX}, 134ef2ee5d0SMichal Meloun {0, UINT_MAX}, 135ef2ee5d0SMichal Meloun }; 136ef2ee5d0SMichal Meloun 137b9cbd68dSMichal Meloun 138ef2ee5d0SMichal Meloun static void 139ef2ee5d0SMichal Meloun tegra124_rev_sku_to_speedo_ids(struct tegra_efuse_softc *sc, 140ef2ee5d0SMichal Meloun struct tegra_sku_info *sku, int *threshold) 141ef2ee5d0SMichal Meloun { 142ef2ee5d0SMichal Meloun 143b9cbd68dSMichal Meloun /* Set default */ 144ef2ee5d0SMichal Meloun sku->cpu_speedo_id = 0; 145ef2ee5d0SMichal Meloun sku->soc_speedo_id = 0; 146ef2ee5d0SMichal Meloun sku->gpu_speedo_id = 0; 147ef2ee5d0SMichal Meloun *threshold = TEGRA124_THRESHOLD_INDEX_0; 148ef2ee5d0SMichal Meloun 149ef2ee5d0SMichal Meloun switch (sku->sku_id) { 150ef2ee5d0SMichal Meloun case 0x00: /* Eng sku */ 151ef2ee5d0SMichal Meloun case 0x0F: 152ef2ee5d0SMichal Meloun case 0x23: 153ef2ee5d0SMichal Meloun /* Using the default */ 154ef2ee5d0SMichal Meloun break; 155ef2ee5d0SMichal Meloun case 0x83: 156ef2ee5d0SMichal Meloun sku->cpu_speedo_id = 2; 157ef2ee5d0SMichal Meloun break; 158ef2ee5d0SMichal Meloun 159ef2ee5d0SMichal Meloun case 0x1F: 160ef2ee5d0SMichal Meloun case 0x87: 161ef2ee5d0SMichal Meloun case 0x27: 162ef2ee5d0SMichal Meloun sku->cpu_speedo_id = 2; 163ef2ee5d0SMichal Meloun sku->soc_speedo_id = 0; 164ef2ee5d0SMichal Meloun sku->gpu_speedo_id = 1; 165ef2ee5d0SMichal Meloun *threshold = TEGRA124_THRESHOLD_INDEX_0; 166ef2ee5d0SMichal Meloun break; 167ef2ee5d0SMichal Meloun case 0x81: 168ef2ee5d0SMichal Meloun case 0x21: 169ef2ee5d0SMichal Meloun case 0x07: 170ef2ee5d0SMichal Meloun sku->cpu_speedo_id = 1; 171ef2ee5d0SMichal Meloun sku->soc_speedo_id = 1; 172ef2ee5d0SMichal Meloun sku->gpu_speedo_id = 1; 173ef2ee5d0SMichal Meloun *threshold = TEGRA124_THRESHOLD_INDEX_1; 174ef2ee5d0SMichal Meloun break; 175ef2ee5d0SMichal Meloun case 0x49: 176ef2ee5d0SMichal Meloun case 0x4A: 177ef2ee5d0SMichal Meloun case 0x48: 178ef2ee5d0SMichal Meloun sku->cpu_speedo_id = 4; 179ef2ee5d0SMichal Meloun sku->soc_speedo_id = 2; 180ef2ee5d0SMichal Meloun sku->gpu_speedo_id = 3; 181ef2ee5d0SMichal Meloun *threshold = TEGRA124_THRESHOLD_INDEX_1; 182ef2ee5d0SMichal Meloun break; 183ef2ee5d0SMichal Meloun default: 184ef2ee5d0SMichal Meloun device_printf(sc->dev, " Unknown SKU ID %d\n", sku->sku_id); 185ef2ee5d0SMichal Meloun break; 186ef2ee5d0SMichal Meloun } 187ef2ee5d0SMichal Meloun } 188ef2ee5d0SMichal Meloun 189ef2ee5d0SMichal Meloun static void 190b9cbd68dSMichal Meloun tegra124_init(struct tegra_efuse_softc *sc, struct tegra_sku_info *sku) 191ef2ee5d0SMichal Meloun { 192ef2ee5d0SMichal Meloun int i, threshold; 193ef2ee5d0SMichal Meloun 194ef2ee5d0SMichal Meloun sku->sku_id = RD4(sc, TEGRA124_FUSE_SKU_INFO); 195ef2ee5d0SMichal Meloun sku->soc_iddq_value = RD4(sc, TEGRA124_FUSE_SOC_IDDQ); 196ef2ee5d0SMichal Meloun sku->cpu_iddq_value = RD4(sc, TEGRA124_FUSE_CPU_IDDQ); 197ef2ee5d0SMichal Meloun sku->gpu_iddq_value = RD4(sc, TEGRA124_FUSE_GPU_IDDQ); 198ef2ee5d0SMichal Meloun sku->soc_speedo_value = RD4(sc, TEGRA124_FUSE_SOC_SPEEDO_0); 199ef2ee5d0SMichal Meloun sku->cpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_0); 200ef2ee5d0SMichal Meloun sku->gpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_2); 201ef2ee5d0SMichal Meloun 202ef2ee5d0SMichal Meloun if (sku->cpu_speedo_value == 0) { 203ef2ee5d0SMichal Meloun device_printf(sc->dev, "CPU Speedo value is not fused.\n"); 204ef2ee5d0SMichal Meloun return; 205ef2ee5d0SMichal Meloun } 206ef2ee5d0SMichal Meloun 207ef2ee5d0SMichal Meloun tegra124_rev_sku_to_speedo_ids(sc, sku, &threshold); 208ef2ee5d0SMichal Meloun 209ef2ee5d0SMichal Meloun for (i = 0; i < TEGRA124_SOC_PROCESS_CORNERS; i++) { 210ef2ee5d0SMichal Meloun if (sku->soc_speedo_value < 211ef2ee5d0SMichal Meloun tegra124_soc_process_speedos[threshold][i]) 212ef2ee5d0SMichal Meloun break; 213ef2ee5d0SMichal Meloun } 214ef2ee5d0SMichal Meloun sku->soc_process_id = i; 215ef2ee5d0SMichal Meloun 216ef2ee5d0SMichal Meloun for (i = 0; i < TEGRA124_CPU_PROCESS_CORNERS; i++) { 217ef2ee5d0SMichal Meloun if (sku->cpu_speedo_value < 218ef2ee5d0SMichal Meloun tegra124_cpu_process_speedos[threshold][i]) 219ef2ee5d0SMichal Meloun break; 220ef2ee5d0SMichal Meloun } 221ef2ee5d0SMichal Meloun sku->cpu_process_id = i; 222ef2ee5d0SMichal Meloun 223ef2ee5d0SMichal Meloun for (i = 0; i < TEGRA124_GPU_PROCESS_CORNERS; i++) { 224ef2ee5d0SMichal Meloun if (sku->gpu_speedo_value < 225ef2ee5d0SMichal Meloun tegra124_gpu_process_speedos[threshold][i]) 226ef2ee5d0SMichal Meloun break; 227ef2ee5d0SMichal Meloun } 228ef2ee5d0SMichal Meloun sku->gpu_process_id = i; 229ef2ee5d0SMichal Meloun 230ef2ee5d0SMichal Meloun } 231ef2ee5d0SMichal Meloun /* ----------------- End of Tegra 124 specific code & data --------------- */ 232ef2ee5d0SMichal Meloun 233b9cbd68dSMichal Meloun /* -------------------- Tegra 201 specific code & data ------------------- */ 234b9cbd68dSMichal Meloun #define TEGRA210_CPU_PROCESS_CORNERS 2 235b9cbd68dSMichal Meloun #define TEGRA210_GPU_PROCESS_CORNERS 2 236b9cbd68dSMichal Meloun #define TEGRA210_SOC_PROCESS_CORNERS 3 237b9cbd68dSMichal Meloun 238b9cbd68dSMichal Meloun #define TEGRA210_FUSE_SKU_INFO 0x010 239b9cbd68dSMichal Meloun #define TEGRA210_FUSE_CPU_SPEEDO_0 0x014 240b9cbd68dSMichal Meloun #define TEGRA210_FUSE_CPU_IDDQ 0x018 241b9cbd68dSMichal Meloun #define TEGRA210_FUSE_FT_REV 0x028 242b9cbd68dSMichal Meloun #define TEGRA210_FUSE_CPU_SPEEDO_1 0x02c 243b9cbd68dSMichal Meloun #define TEGRA210_FUSE_CPU_SPEEDO_2 0x030 244b9cbd68dSMichal Meloun #define TEGRA210_FUSE_SOC_SPEEDO_0 0x034 245b9cbd68dSMichal Meloun #define TEGRA210_FUSE_SOC_SPEEDO_1 0x038 246b9cbd68dSMichal Meloun #define TEGRA210_FUSE_SOC_SPEEDO_2 0x03c 247b9cbd68dSMichal Meloun #define TEGRA210_FUSE_SOC_IDDQ 0x040 248b9cbd68dSMichal Meloun #define TEGRA210_FUSE_GPU_IDDQ 0x128 249b9cbd68dSMichal Meloun #define TEGRA210_FUSE_SPARE 0x270 250b9cbd68dSMichal Meloun 251b9cbd68dSMichal Meloun enum { 252b9cbd68dSMichal Meloun TEGRA210_THRESHOLD_INDEX_0, 253b9cbd68dSMichal Meloun TEGRA210_THRESHOLD_INDEX_1, 254b9cbd68dSMichal Meloun TEGRA210_THRESHOLD_INDEX_COUNT, 255b9cbd68dSMichal Meloun }; 256b9cbd68dSMichal Meloun 257b9cbd68dSMichal Meloun static uint32_t tegra210_cpu_process_speedos[][TEGRA210_CPU_PROCESS_CORNERS] = 258b9cbd68dSMichal Meloun { 259b9cbd68dSMichal Meloun {2119, UINT_MAX}, 260b9cbd68dSMichal Meloun {2119, UINT_MAX}, 261b9cbd68dSMichal Meloun }; 262b9cbd68dSMichal Meloun 263b9cbd68dSMichal Meloun static uint32_t tegra210_gpu_process_speedos[][TEGRA210_GPU_PROCESS_CORNERS] = 264b9cbd68dSMichal Meloun { 265b9cbd68dSMichal Meloun {UINT_MAX, UINT_MAX}, 266b9cbd68dSMichal Meloun {UINT_MAX, UINT_MAX}, 267b9cbd68dSMichal Meloun }; 268b9cbd68dSMichal Meloun 269b9cbd68dSMichal Meloun static uint32_t tegra210_soc_process_speedos[][TEGRA210_SOC_PROCESS_CORNERS] = 270b9cbd68dSMichal Meloun { 271b9cbd68dSMichal Meloun {1950, 2100, UINT_MAX}, 272b9cbd68dSMichal Meloun {1950, 2100, UINT_MAX}, 273b9cbd68dSMichal Meloun }; 274b9cbd68dSMichal Meloun 275b9cbd68dSMichal Meloun static uint32_t 276b9cbd68dSMichal Meloun tegra210_get_speedo_revision(struct tegra_efuse_softc *sc) 277b9cbd68dSMichal Meloun { 278b9cbd68dSMichal Meloun uint32_t reg; 279b9cbd68dSMichal Meloun uint32_t val; 280b9cbd68dSMichal Meloun 281b9cbd68dSMichal Meloun val = 0; 282b9cbd68dSMichal Meloun 283b9cbd68dSMichal Meloun /* Revision i encoded in spare fields */ 284b9cbd68dSMichal Meloun reg = RD4(sc, TEGRA210_FUSE_SPARE + 2 * 4); 285b9cbd68dSMichal Meloun val |= (reg & 1) << 0; 286b9cbd68dSMichal Meloun reg = RD4(sc, TEGRA210_FUSE_SPARE + 3 * 4); 287b9cbd68dSMichal Meloun val |= (reg & 1) << 1; 288b9cbd68dSMichal Meloun reg = RD4(sc, TEGRA210_FUSE_SPARE + 4 * 4); 289b9cbd68dSMichal Meloun val |= (reg & 1) << 2; 290b9cbd68dSMichal Meloun 291b9cbd68dSMichal Meloun return (val); 292b9cbd68dSMichal Meloun } 293b9cbd68dSMichal Meloun 294b9cbd68dSMichal Meloun 295b9cbd68dSMichal Meloun static void 296b9cbd68dSMichal Meloun tegra210_rev_sku_to_speedo_ids(struct tegra_efuse_softc *sc, 297b9cbd68dSMichal Meloun struct tegra_sku_info *sku, int speedo_rev, int *threshold) 298b9cbd68dSMichal Meloun { 299b9cbd68dSMichal Meloun 300b9cbd68dSMichal Meloun /* Set defaults */ 301b9cbd68dSMichal Meloun sku->cpu_speedo_id = 0; 302b9cbd68dSMichal Meloun sku->soc_speedo_id = 0; 303b9cbd68dSMichal Meloun sku->gpu_speedo_id = 0; 304b9cbd68dSMichal Meloun *threshold = TEGRA210_THRESHOLD_INDEX_0; 305b9cbd68dSMichal Meloun 306b9cbd68dSMichal Meloun switch (sku->sku_id) { 307b9cbd68dSMichal Meloun case 0x00: /* Eng sku */ 308b9cbd68dSMichal Meloun case 0x01: /* Eng sku */ 309b9cbd68dSMichal Meloun case 0x07: 310b9cbd68dSMichal Meloun case 0x17: 311b9cbd68dSMichal Meloun case 0x27: 312b9cbd68dSMichal Meloun /* Use defaults */ 313b9cbd68dSMichal Meloun if (speedo_rev >= 2) 314b9cbd68dSMichal Meloun sku->gpu_speedo_id = 1; 315b9cbd68dSMichal Meloun break; 316b9cbd68dSMichal Meloun case 0x13: 317b9cbd68dSMichal Meloun if (speedo_rev >= 2) 318b9cbd68dSMichal Meloun sku->gpu_speedo_id = 1; 319b9cbd68dSMichal Meloun sku->cpu_speedo_id = 1; 320b9cbd68dSMichal Meloun break; 321b9cbd68dSMichal Meloun 322b9cbd68dSMichal Meloun default: 323b9cbd68dSMichal Meloun device_printf(sc->dev, " Unknown SKU ID %d\n", sku->sku_id); 324b9cbd68dSMichal Meloun break; 325b9cbd68dSMichal Meloun } 326b9cbd68dSMichal Meloun } 327b9cbd68dSMichal Meloun 328b9cbd68dSMichal Meloun 329b9cbd68dSMichal Meloun static void 330b9cbd68dSMichal Meloun tegra210_init(struct tegra_efuse_softc *sc, struct tegra_sku_info *sku) 331b9cbd68dSMichal Meloun { 332b9cbd68dSMichal Meloun int i, threshold, speedo_rev; 333b9cbd68dSMichal Meloun uint32_t cpu_speedo[3], soc_speedo[3]; 334b9cbd68dSMichal Meloun 335b9cbd68dSMichal Meloun cpu_speedo[0] = RD4(sc, TEGRA210_FUSE_CPU_SPEEDO_0); 336b9cbd68dSMichal Meloun cpu_speedo[1] = RD4(sc, TEGRA210_FUSE_CPU_SPEEDO_1); 337b9cbd68dSMichal Meloun cpu_speedo[2] = RD4(sc, TEGRA210_FUSE_CPU_SPEEDO_2); 338b9cbd68dSMichal Meloun soc_speedo[0] = RD4(sc, TEGRA210_FUSE_SOC_SPEEDO_0); 339b9cbd68dSMichal Meloun soc_speedo[1] = RD4(sc, TEGRA210_FUSE_SOC_SPEEDO_1); 340b9cbd68dSMichal Meloun soc_speedo[2] = RD4(sc, TEGRA210_FUSE_SOC_SPEEDO_2); 341b9cbd68dSMichal Meloun 342b9cbd68dSMichal Meloun 343b9cbd68dSMichal Meloun sku->cpu_iddq_value = RD4(sc, TEGRA210_FUSE_CPU_IDDQ); 344b9cbd68dSMichal Meloun sku->soc_iddq_value = RD4(sc, TEGRA210_FUSE_SOC_IDDQ); 345b9cbd68dSMichal Meloun sku->gpu_iddq_value = RD4(sc, TEGRA210_FUSE_GPU_IDDQ); 346b9cbd68dSMichal Meloun 347b9cbd68dSMichal Meloun speedo_rev = tegra210_get_speedo_revision(sc); 348b9cbd68dSMichal Meloun device_printf(sc->dev, " Speedo revision: %u\n", speedo_rev); 349b9cbd68dSMichal Meloun 350b9cbd68dSMichal Meloun if (speedo_rev >= 3) { 351b9cbd68dSMichal Meloun sku->cpu_speedo_value = cpu_speedo[0]; 352b9cbd68dSMichal Meloun sku->gpu_speedo_value = cpu_speedo[2]; 353b9cbd68dSMichal Meloun sku->soc_speedo_value = soc_speedo[0]; 354b9cbd68dSMichal Meloun } else if (speedo_rev == 2) { 355b9cbd68dSMichal Meloun sku->cpu_speedo_value = 356b9cbd68dSMichal Meloun (-1938 + (1095 * cpu_speedo[0] / 100)) / 10; 357b9cbd68dSMichal Meloun sku->gpu_speedo_value = 358b9cbd68dSMichal Meloun (-1662 + (1082 * cpu_speedo[2] / 100)) / 10; 359b9cbd68dSMichal Meloun sku->soc_speedo_value = 360b9cbd68dSMichal Meloun ( -705 + (1037 * soc_speedo[0] / 100)) / 10; 361b9cbd68dSMichal Meloun } else { 362b9cbd68dSMichal Meloun sku->cpu_speedo_value = 2100; 363b9cbd68dSMichal Meloun sku->gpu_speedo_value = cpu_speedo[2] - 75; 364b9cbd68dSMichal Meloun sku->soc_speedo_value = 1900; 365b9cbd68dSMichal Meloun } 366b9cbd68dSMichal Meloun 367b9cbd68dSMichal Meloun tegra210_rev_sku_to_speedo_ids(sc, sku, speedo_rev, &threshold); 368b9cbd68dSMichal Meloun 369b9cbd68dSMichal Meloun for (i = 0; i < TEGRA210_SOC_PROCESS_CORNERS; i++) { 370b9cbd68dSMichal Meloun if (sku->soc_speedo_value < 371b9cbd68dSMichal Meloun tegra210_soc_process_speedos[threshold][i]) 372b9cbd68dSMichal Meloun break; 373b9cbd68dSMichal Meloun } 374b9cbd68dSMichal Meloun sku->soc_process_id = i; 375b9cbd68dSMichal Meloun 376b9cbd68dSMichal Meloun for (i = 0; i < TEGRA210_CPU_PROCESS_CORNERS; i++) { 377b9cbd68dSMichal Meloun if (sku->cpu_speedo_value < 378b9cbd68dSMichal Meloun tegra210_cpu_process_speedos[threshold][i]) 379b9cbd68dSMichal Meloun break; 380b9cbd68dSMichal Meloun } 381b9cbd68dSMichal Meloun sku->cpu_process_id = i; 382b9cbd68dSMichal Meloun 383b9cbd68dSMichal Meloun for (i = 0; i < TEGRA210_GPU_PROCESS_CORNERS; i++) { 384b9cbd68dSMichal Meloun if (sku->gpu_speedo_value < 385b9cbd68dSMichal Meloun tegra210_gpu_process_speedos[threshold][i]) 386b9cbd68dSMichal Meloun break; 387b9cbd68dSMichal Meloun } 388b9cbd68dSMichal Meloun sku->gpu_process_id = i; 389b9cbd68dSMichal Meloun 390b9cbd68dSMichal Meloun } 391b9cbd68dSMichal Meloun 392b9cbd68dSMichal Meloun /* ----------------- End of Tegra 210 specific code & data --------------- */ 393b9cbd68dSMichal Meloun 394b9cbd68dSMichal Meloun 395ef2ee5d0SMichal Meloun uint32_t 396ef2ee5d0SMichal Meloun tegra_fuse_read_4(int addr) { 397ef2ee5d0SMichal Meloun if (dev_sc == NULL) 398ef2ee5d0SMichal Meloun panic("tegra_fuse_read_4 called too early"); 399ef2ee5d0SMichal Meloun return (RD4(dev_sc, addr)); 400ef2ee5d0SMichal Meloun } 401ef2ee5d0SMichal Meloun 402ef2ee5d0SMichal Meloun static void 40359249a51SAndrew Turner tegra_efuse_dump_sku(void) 404ef2ee5d0SMichal Meloun { 405ef2ee5d0SMichal Meloun printf(" TEGRA SKU Info:\n"); 406ef2ee5d0SMichal Meloun printf(" chip_id: %u\n", tegra_sku_info.chip_id); 407ef2ee5d0SMichal Meloun printf(" sku_id: %u\n", tegra_sku_info.sku_id); 408ef2ee5d0SMichal Meloun printf(" cpu_process_id: %u\n", tegra_sku_info.cpu_process_id); 409ef2ee5d0SMichal Meloun printf(" cpu_speedo_id: %u\n", tegra_sku_info.cpu_speedo_id); 410ef2ee5d0SMichal Meloun printf(" cpu_speedo_value: %u\n", tegra_sku_info.cpu_speedo_value); 411ef2ee5d0SMichal Meloun printf(" cpu_iddq_value: %u\n", tegra_sku_info.cpu_iddq_value); 412ef2ee5d0SMichal Meloun printf(" soc_process_id: %u\n", tegra_sku_info.soc_process_id); 413ef2ee5d0SMichal Meloun printf(" soc_speedo_id: %u\n", tegra_sku_info.soc_speedo_id); 414ef2ee5d0SMichal Meloun printf(" soc_speedo_value: %u\n", tegra_sku_info.soc_speedo_value); 415ef2ee5d0SMichal Meloun printf(" soc_iddq_value: %u\n", tegra_sku_info.soc_iddq_value); 416ef2ee5d0SMichal Meloun printf(" gpu_process_id: %u\n", tegra_sku_info.gpu_process_id); 417ef2ee5d0SMichal Meloun printf(" gpu_speedo_id: %u\n", tegra_sku_info.gpu_speedo_id); 418ef2ee5d0SMichal Meloun printf(" gpu_speedo_value: %u\n", tegra_sku_info.gpu_speedo_value); 419ef2ee5d0SMichal Meloun printf(" gpu_iddq_value: %u\n", tegra_sku_info.gpu_iddq_value); 420ef2ee5d0SMichal Meloun printf(" revision: %s\n", tegra_rev_name[tegra_sku_info.revision]); 421ef2ee5d0SMichal Meloun } 422ef2ee5d0SMichal Meloun 423ef2ee5d0SMichal Meloun static int 424ef2ee5d0SMichal Meloun tegra_efuse_probe(device_t dev) 425ef2ee5d0SMichal Meloun { 426ef2ee5d0SMichal Meloun if (!ofw_bus_status_okay(dev)) 427ef2ee5d0SMichal Meloun return (ENXIO); 428ef2ee5d0SMichal Meloun 429ef2ee5d0SMichal Meloun if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 430ef2ee5d0SMichal Meloun return (ENXIO); 431ef2ee5d0SMichal Meloun 432ef2ee5d0SMichal Meloun return (BUS_PROBE_DEFAULT); 433ef2ee5d0SMichal Meloun } 434ef2ee5d0SMichal Meloun 435ef2ee5d0SMichal Meloun static int 436ef2ee5d0SMichal Meloun tegra_efuse_attach(device_t dev) 437ef2ee5d0SMichal Meloun { 438ef2ee5d0SMichal Meloun int rv, rid; 439ef2ee5d0SMichal Meloun struct tegra_efuse_softc *sc; 440ef2ee5d0SMichal Meloun 441ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 442ef2ee5d0SMichal Meloun sc->dev = dev; 443b9cbd68dSMichal Meloun sc->soc = (struct efuse_soc *)ofw_bus_search_compatible(dev, 444b9cbd68dSMichal Meloun compat_data)->ocd_data; 445ef2ee5d0SMichal Meloun 446ef2ee5d0SMichal Meloun /* Get the memory resource for the register mapping. */ 447ef2ee5d0SMichal Meloun rid = 0; 448ef2ee5d0SMichal Meloun sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 449ef2ee5d0SMichal Meloun RF_ACTIVE); 450ef2ee5d0SMichal Meloun if (sc->mem_res == NULL) { 451ef2ee5d0SMichal Meloun device_printf(dev, "Cannot map registers.\n"); 452ef2ee5d0SMichal Meloun rv = ENXIO; 453ef2ee5d0SMichal Meloun goto fail; 454ef2ee5d0SMichal Meloun } 455ef2ee5d0SMichal Meloun 456ef2ee5d0SMichal Meloun /* OFW resources. */ 457dac93553SMichal Meloun rv = clk_get_by_ofw_name(dev, 0, "fuse", &sc->clk); 458ef2ee5d0SMichal Meloun if (rv != 0) { 459ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get fuse clock: %d\n", rv); 460ef2ee5d0SMichal Meloun goto fail; 461ef2ee5d0SMichal Meloun } 462ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk); 463ef2ee5d0SMichal Meloun if (rv != 0) { 464ef2ee5d0SMichal Meloun device_printf(dev, "Cannot enable clock: %d\n", rv); 465ef2ee5d0SMichal Meloun goto fail; 466ef2ee5d0SMichal Meloun } 467dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(sc->dev, 0, "fuse", &sc->reset); 468ef2ee5d0SMichal Meloun if (rv != 0) { 469ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get fuse reset\n"); 470ef2ee5d0SMichal Meloun goto fail; 471ef2ee5d0SMichal Meloun } 472ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->reset); 473ef2ee5d0SMichal Meloun if (rv != 0) { 474ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot clear reset\n"); 475ef2ee5d0SMichal Meloun goto fail; 476ef2ee5d0SMichal Meloun } 477ef2ee5d0SMichal Meloun 478b9cbd68dSMichal Meloun sc->soc->init(sc, &tegra_sku_info); 479ef2ee5d0SMichal Meloun 480ef2ee5d0SMichal Meloun dev_sc = sc; 481ef2ee5d0SMichal Meloun 482ef2ee5d0SMichal Meloun if (bootverbose) 483ef2ee5d0SMichal Meloun tegra_efuse_dump_sku(); 484*18250ec6SJohn Baldwin bus_attach_children(dev); 485*18250ec6SJohn Baldwin return (0); 486ef2ee5d0SMichal Meloun 487ef2ee5d0SMichal Meloun fail: 488ef2ee5d0SMichal Meloun dev_sc = NULL; 489ef2ee5d0SMichal Meloun if (sc->clk != NULL) 490ef2ee5d0SMichal Meloun clk_release(sc->clk); 491ef2ee5d0SMichal Meloun if (sc->reset != NULL) 492ef2ee5d0SMichal Meloun hwreset_release(sc->reset); 493ef2ee5d0SMichal Meloun if (sc->mem_res != NULL) 494ef2ee5d0SMichal Meloun bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 495ef2ee5d0SMichal Meloun 496ef2ee5d0SMichal Meloun return (rv); 497ef2ee5d0SMichal Meloun } 498ef2ee5d0SMichal Meloun 499ef2ee5d0SMichal Meloun static int 500ef2ee5d0SMichal Meloun tegra_efuse_detach(device_t dev) 501ef2ee5d0SMichal Meloun { 502ef2ee5d0SMichal Meloun struct tegra_efuse_softc *sc; 503d412c076SJohn Baldwin int error; 504d412c076SJohn Baldwin 505d412c076SJohn Baldwin error = bus_generic_detach(dev); 506d412c076SJohn Baldwin if (error != 0) 507d412c076SJohn Baldwin return (error); 508ef2ee5d0SMichal Meloun 509ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 510ef2ee5d0SMichal Meloun dev_sc = NULL; 511ef2ee5d0SMichal Meloun if (sc->clk != NULL) 512ef2ee5d0SMichal Meloun clk_release(sc->clk); 513ef2ee5d0SMichal Meloun if (sc->reset != NULL) 514ef2ee5d0SMichal Meloun hwreset_release(sc->reset); 515ef2ee5d0SMichal Meloun if (sc->mem_res != NULL) 516ef2ee5d0SMichal Meloun bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 517ef2ee5d0SMichal Meloun 518d412c076SJohn Baldwin return (0); 519ef2ee5d0SMichal Meloun } 520ef2ee5d0SMichal Meloun 521ef2ee5d0SMichal Meloun static device_method_t tegra_efuse_methods[] = { 522ef2ee5d0SMichal Meloun /* Device interface */ 523ef2ee5d0SMichal Meloun DEVMETHOD(device_probe, tegra_efuse_probe), 524ef2ee5d0SMichal Meloun DEVMETHOD(device_attach, tegra_efuse_attach), 525ef2ee5d0SMichal Meloun DEVMETHOD(device_detach, tegra_efuse_detach), 526ef2ee5d0SMichal Meloun 527ef2ee5d0SMichal Meloun DEVMETHOD_END 528ef2ee5d0SMichal Meloun }; 529ef2ee5d0SMichal Meloun 5304bda238aSMichal Meloun static DEFINE_CLASS_0(efuse, tegra_efuse_driver, tegra_efuse_methods, 5314bda238aSMichal Meloun sizeof(struct tegra_efuse_softc)); 532289f133bSJohn Baldwin EARLY_DRIVER_MODULE(tegra_efuse, simplebus, tegra_efuse_driver, NULL, NULL, 533289f133bSJohn Baldwin BUS_PASS_TIMER); 534