1296936Smmel/*- 2296936Smmel * Copyright (c) 2015 Michal Meloun 3296936Smmel * All rights reserved. 4296936Smmel * 5296936Smmel * Redistribution and use in source and binary forms, with or without 6296936Smmel * modification, are permitted provided that the following conditions 7296936Smmel * are met: 8296936Smmel * 1. Redistributions of source code must retain the above copyright 9296936Smmel * notice, this list of conditions and the following disclaimer. 10296936Smmel * 2. Redistributions in binary form must reproduce the above copyright 11296936Smmel * notice, this list of conditions and the following disclaimer in the 12296936Smmel * documentation and/or other materials provided with the distribution. 13296936Smmel * 14296936Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15296936Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16296936Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17296936Smmel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18296936Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19296936Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20296936Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21296936Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22296936Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23296936Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24296936Smmel * SUCH DAMAGE. 25296936Smmel */ 26296936Smmel 27296936Smmel#include <sys/cdefs.h> 28296936Smmel__FBSDID("$FreeBSD: stable/11/sys/arm/nvidia/tegra_efuse.c 314506 2017-03-01 19:55:04Z ian $"); 29296936Smmel 30296936Smmel#include <sys/param.h> 31296936Smmel#include <sys/systm.h> 32296936Smmel#include <sys/bus.h> 33296936Smmel#include <sys/clock.h> 34296936Smmel#include <sys/kernel.h> 35296936Smmel#include <sys/limits.h> 36296936Smmel#include <sys/lock.h> 37296936Smmel#include <sys/mutex.h> 38296936Smmel#include <sys/module.h> 39296936Smmel#include <sys/resource.h> 40296936Smmel#include <sys/rman.h> 41296936Smmel 42296936Smmel#include <machine/bus.h> 43296936Smmel#include <machine/resource.h> 44296936Smmel 45296936Smmel#include <dev/extres/clk/clk.h> 46296936Smmel#include <dev/extres/hwreset/hwreset.h> 47296936Smmel#include <dev/fdt/fdt_common.h> 48296936Smmel#include <dev/ofw/ofw_bus.h> 49296936Smmel#include <dev/ofw/ofw_bus_subr.h> 50296936Smmel 51296936Smmel#include <arm/nvidia/tegra_efuse.h> 52296936Smmel 53296936Smmel 54296936Smmel#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_sc)->fuse_begin + (_r)) 55296936Smmel 56296936Smmelstatic struct ofw_compat_data compat_data[] = { 57296936Smmel {"nvidia,tegra124-efuse", 1}, 58296936Smmel {NULL, 0} 59296936Smmel}; 60296936Smmel 61296936Smmelstruct tegra_efuse_softc { 62296936Smmel device_t dev; 63296936Smmel struct resource *mem_res; 64296936Smmel 65296936Smmel int fuse_begin; 66296936Smmel clk_t clk; 67296936Smmel hwreset_t reset; 68296936Smmel}; 69296936Smmelstruct tegra_efuse_softc *dev_sc; 70296936Smmel 71296936Smmelstruct tegra_sku_info tegra_sku_info; 72296936Smmelstatic char *tegra_rev_name[] = { 73296936Smmel [TEGRA_REVISION_UNKNOWN] = "unknown", 74296936Smmel [TEGRA_REVISION_A01] = "A01", 75296936Smmel [TEGRA_REVISION_A02] = "A02", 76296936Smmel [TEGRA_REVISION_A03] = "A03", 77296936Smmel [TEGRA_REVISION_A03p] = "A03 prime", 78296936Smmel [TEGRA_REVISION_A04] = "A04", 79296936Smmel}; 80296936Smmel 81296936Smmel/* Tegra30 and later */ 82296936Smmel#define FUSE_VENDOR_CODE 0x100 83296936Smmel#define FUSE_FAB_CODE 0x104 84296936Smmel#define FUSE_LOT_CODE_0 0x108 85296936Smmel#define FUSE_LOT_CODE_1 0x10c 86296936Smmel#define FUSE_WAFER_ID 0x110 87296936Smmel#define FUSE_X_COORDINATE 0x114 88296936Smmel#define FUSE_Y_COORDINATE 0x118 89296936Smmel 90296936Smmel/* ---------------------- Tegra 124 specific code & data --------------- */ 91296936Smmel#define TEGRA124_FUSE_BEGIN 0x100 92296936Smmel 93296936Smmel#define TEGRA124_CPU_PROCESS_CORNERS 2 94296936Smmel#define TEGRA124_GPU_PROCESS_CORNERS 2 95296936Smmel#define TEGRA124_SOC_PROCESS_CORNERS 2 96296936Smmel 97296936Smmel#define TEGRA124_FUSE_SKU_INFO 0x10 98296936Smmel#define TEGRA124_FUSE_CPU_SPEEDO_0 0x14 99296936Smmel#define TEGRA124_FUSE_CPU_IDDQ 0x18 100296936Smmel#define TEGRA124_FUSE_FT_REV 0x28 101296936Smmel#define TEGRA124_FUSE_CPU_SPEEDO_1 0x2c 102296936Smmel#define TEGRA124_FUSE_CPU_SPEEDO_2 0x30 103296936Smmel#define TEGRA124_FUSE_SOC_SPEEDO_0 0x34 104296936Smmel#define TEGRA124_FUSE_SOC_SPEEDO_1 0x38 105296936Smmel#define TEGRA124_FUSE_SOC_SPEEDO_2 0x3c 106296936Smmel#define TEGRA124_FUSE_SOC_IDDQ 0x40 107296936Smmel#define TEGRA124_FUSE_GPU_IDDQ 0x128 108296936Smmel 109296936Smmelenum { 110296936Smmel TEGRA124_THRESHOLD_INDEX_0, 111296936Smmel TEGRA124_THRESHOLD_INDEX_1, 112296936Smmel TEGRA124_THRESHOLD_INDEX_COUNT, 113296936Smmel}; 114296936Smmel 115296936Smmelstatic uint32_t tegra124_cpu_process_speedos[][TEGRA124_CPU_PROCESS_CORNERS] = 116296936Smmel{ 117296936Smmel {2190, UINT_MAX}, 118296936Smmel {0, UINT_MAX}, 119296936Smmel}; 120296936Smmel 121296936Smmelstatic uint32_t tegra124_gpu_process_speedos[][TEGRA124_GPU_PROCESS_CORNERS] = 122296936Smmel{ 123296936Smmel {1965, UINT_MAX}, 124296936Smmel {0, UINT_MAX}, 125296936Smmel}; 126296936Smmel 127296936Smmelstatic uint32_t tegra124_soc_process_speedos[][TEGRA124_SOC_PROCESS_CORNERS] = 128296936Smmel{ 129296936Smmel {2101, UINT_MAX}, 130296936Smmel {0, UINT_MAX}, 131296936Smmel}; 132296936Smmel 133296936Smmelstatic void 134296936Smmeltegra124_rev_sku_to_speedo_ids(struct tegra_efuse_softc *sc, 135296936Smmel struct tegra_sku_info *sku, int *threshold) 136296936Smmel{ 137296936Smmel 138296936Smmel /* Assign to default */ 139296936Smmel sku->cpu_speedo_id = 0; 140296936Smmel sku->soc_speedo_id = 0; 141296936Smmel sku->gpu_speedo_id = 0; 142296936Smmel *threshold = TEGRA124_THRESHOLD_INDEX_0; 143296936Smmel 144296936Smmel switch (sku->sku_id) { 145296936Smmel case 0x00: /* Eng sku */ 146296936Smmel case 0x0F: 147296936Smmel case 0x23: 148296936Smmel /* Using the default */ 149296936Smmel break; 150296936Smmel case 0x83: 151296936Smmel sku->cpu_speedo_id = 2; 152296936Smmel break; 153296936Smmel 154296936Smmel case 0x1F: 155296936Smmel case 0x87: 156296936Smmel case 0x27: 157296936Smmel sku->cpu_speedo_id = 2; 158296936Smmel sku->soc_speedo_id = 0; 159296936Smmel sku->gpu_speedo_id = 1; 160296936Smmel *threshold = TEGRA124_THRESHOLD_INDEX_0; 161296936Smmel break; 162296936Smmel case 0x81: 163296936Smmel case 0x21: 164296936Smmel case 0x07: 165296936Smmel sku->cpu_speedo_id = 1; 166296936Smmel sku->soc_speedo_id = 1; 167296936Smmel sku->gpu_speedo_id = 1; 168296936Smmel *threshold = TEGRA124_THRESHOLD_INDEX_1; 169296936Smmel break; 170296936Smmel case 0x49: 171296936Smmel case 0x4A: 172296936Smmel case 0x48: 173296936Smmel sku->cpu_speedo_id = 4; 174296936Smmel sku->soc_speedo_id = 2; 175296936Smmel sku->gpu_speedo_id = 3; 176296936Smmel *threshold = TEGRA124_THRESHOLD_INDEX_1; 177296936Smmel break; 178296936Smmel default: 179296936Smmel device_printf(sc->dev, " Unknown SKU ID %d\n", sku->sku_id); 180296936Smmel break; 181296936Smmel } 182296936Smmel} 183296936Smmel 184296936Smmel 185296936Smmelstatic void 186296936Smmeltegra124_init_speedo(struct tegra_efuse_softc *sc, struct tegra_sku_info *sku) 187296936Smmel{ 188296936Smmel int i, threshold; 189296936Smmel 190296936Smmel sku->sku_id = RD4(sc, TEGRA124_FUSE_SKU_INFO); 191296936Smmel sku->soc_iddq_value = RD4(sc, TEGRA124_FUSE_SOC_IDDQ); 192296936Smmel sku->cpu_iddq_value = RD4(sc, TEGRA124_FUSE_CPU_IDDQ); 193296936Smmel sku->gpu_iddq_value = RD4(sc, TEGRA124_FUSE_GPU_IDDQ); 194296936Smmel sku->soc_speedo_value = RD4(sc, TEGRA124_FUSE_SOC_SPEEDO_0); 195296936Smmel sku->cpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_0); 196296936Smmel sku->gpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_2); 197296936Smmel 198296936Smmel if (sku->cpu_speedo_value == 0) { 199296936Smmel device_printf(sc->dev, "CPU Speedo value is not fused.\n"); 200296936Smmel return; 201296936Smmel } 202296936Smmel 203296936Smmel tegra124_rev_sku_to_speedo_ids(sc, sku, &threshold); 204296936Smmel 205296936Smmel for (i = 0; i < TEGRA124_SOC_PROCESS_CORNERS; i++) { 206296936Smmel if (sku->soc_speedo_value < 207296936Smmel tegra124_soc_process_speedos[threshold][i]) 208296936Smmel break; 209296936Smmel } 210296936Smmel sku->soc_process_id = i; 211296936Smmel 212296936Smmel for (i = 0; i < TEGRA124_CPU_PROCESS_CORNERS; i++) { 213296936Smmel if (sku->cpu_speedo_value < 214296936Smmel tegra124_cpu_process_speedos[threshold][i]) 215296936Smmel break; 216296936Smmel } 217296936Smmel sku->cpu_process_id = i; 218296936Smmel 219296936Smmel for (i = 0; i < TEGRA124_GPU_PROCESS_CORNERS; i++) { 220296936Smmel if (sku->gpu_speedo_value < 221296936Smmel tegra124_gpu_process_speedos[threshold][i]) 222296936Smmel break; 223296936Smmel } 224296936Smmel sku->gpu_process_id = i; 225296936Smmel 226296936Smmel} 227296936Smmel 228296936Smmel/* ----------------- End of Tegra 124 specific code & data --------------- */ 229296936Smmel 230296936Smmeluint32_t 231296936Smmeltegra_fuse_read_4(int addr) { 232296936Smmel 233296936Smmel if (dev_sc == NULL) 234296936Smmel panic("tegra_fuse_read_4 called too early"); 235296936Smmel return (RD4(dev_sc, addr)); 236296936Smmel} 237296936Smmel 238296936Smmel 239296936Smmelstatic void 240314506Siantegra_efuse_dump_sku(void) 241296936Smmel{ 242296936Smmel printf(" TEGRA SKU Info:\n"); 243296936Smmel printf(" chip_id: %u\n", tegra_sku_info.chip_id); 244296936Smmel printf(" sku_id: %u\n", tegra_sku_info.sku_id); 245296936Smmel printf(" cpu_process_id: %u\n", tegra_sku_info.cpu_process_id); 246296936Smmel printf(" cpu_speedo_id: %u\n", tegra_sku_info.cpu_speedo_id); 247296936Smmel printf(" cpu_speedo_value: %u\n", tegra_sku_info.cpu_speedo_value); 248296936Smmel printf(" cpu_iddq_value: %u\n", tegra_sku_info.cpu_iddq_value); 249296936Smmel printf(" soc_process_id: %u\n", tegra_sku_info.soc_process_id); 250296936Smmel printf(" soc_speedo_id: %u\n", tegra_sku_info.soc_speedo_id); 251296936Smmel printf(" soc_speedo_value: %u\n", tegra_sku_info.soc_speedo_value); 252296936Smmel printf(" soc_iddq_value: %u\n", tegra_sku_info.soc_iddq_value); 253296936Smmel printf(" gpu_process_id: %u\n", tegra_sku_info.gpu_process_id); 254296936Smmel printf(" gpu_speedo_id: %u\n", tegra_sku_info.gpu_speedo_id); 255296936Smmel printf(" gpu_speedo_value: %u\n", tegra_sku_info.gpu_speedo_value); 256296936Smmel printf(" gpu_iddq_value: %u\n", tegra_sku_info.gpu_iddq_value); 257296936Smmel printf(" revision: %s\n", tegra_rev_name[tegra_sku_info.revision]); 258296936Smmel} 259296936Smmel 260296936Smmelstatic int 261296936Smmeltegra_efuse_probe(device_t dev) 262296936Smmel{ 263296936Smmel if (!ofw_bus_status_okay(dev)) 264296936Smmel return (ENXIO); 265296936Smmel 266296936Smmel if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 267296936Smmel return (ENXIO); 268296936Smmel 269296936Smmel return (BUS_PROBE_DEFAULT); 270296936Smmel} 271296936Smmel 272296936Smmelstatic int 273296936Smmeltegra_efuse_attach(device_t dev) 274296936Smmel{ 275296936Smmel int rv, rid; 276296936Smmel phandle_t node; 277296936Smmel struct tegra_efuse_softc *sc; 278296936Smmel 279296936Smmel sc = device_get_softc(dev); 280296936Smmel sc->dev = dev; 281296936Smmel node = ofw_bus_get_node(dev); 282296936Smmel 283296936Smmel /* Get the memory resource for the register mapping. */ 284296936Smmel rid = 0; 285296936Smmel sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 286296936Smmel RF_ACTIVE); 287296936Smmel if (sc->mem_res == NULL) { 288296936Smmel device_printf(dev, "Cannot map registers.\n"); 289296936Smmel rv = ENXIO; 290296936Smmel goto fail; 291296936Smmel } 292296936Smmel 293296936Smmel /* OFW resources. */ 294308324Smmel rv = clk_get_by_ofw_name(dev, 0, "fuse", &sc->clk); 295296936Smmel if (rv != 0) { 296296936Smmel device_printf(dev, "Cannot get fuse clock: %d\n", rv); 297296936Smmel goto fail; 298296936Smmel } 299296936Smmel rv = clk_enable(sc->clk); 300296936Smmel if (rv != 0) { 301296936Smmel device_printf(dev, "Cannot enable clock: %d\n", rv); 302296936Smmel goto fail; 303296936Smmel } 304308324Smmel rv = hwreset_get_by_ofw_name(sc->dev, 0, "fuse", &sc->reset); 305296936Smmel if (rv != 0) { 306296936Smmel device_printf(dev, "Cannot get fuse reset\n"); 307296936Smmel goto fail; 308296936Smmel } 309296936Smmel rv = hwreset_deassert(sc->reset); 310296936Smmel if (rv != 0) { 311296936Smmel device_printf(sc->dev, "Cannot clear reset\n"); 312296936Smmel goto fail; 313296936Smmel } 314296936Smmel 315296936Smmel /* Tegra124 specific init. */ 316296936Smmel sc->fuse_begin = TEGRA124_FUSE_BEGIN; 317296936Smmel tegra124_init_speedo(sc, &tegra_sku_info); 318296936Smmel 319296936Smmel dev_sc = sc; 320296936Smmel 321296936Smmel if (bootverbose) 322296936Smmel tegra_efuse_dump_sku(); 323296936Smmel return (bus_generic_attach(dev)); 324296936Smmel 325296936Smmelfail: 326296936Smmel dev_sc = NULL; 327296936Smmel if (sc->clk != NULL) 328296936Smmel clk_release(sc->clk); 329296936Smmel if (sc->reset != NULL) 330296936Smmel hwreset_release(sc->reset); 331296936Smmel if (sc->mem_res != NULL) 332296936Smmel bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 333296936Smmel 334296936Smmel return (rv); 335296936Smmel} 336296936Smmel 337296936Smmelstatic int 338296936Smmeltegra_efuse_detach(device_t dev) 339296936Smmel{ 340296936Smmel struct tegra_efuse_softc *sc; 341296936Smmel 342296936Smmel sc = device_get_softc(dev); 343296936Smmel dev_sc = NULL; 344296936Smmel if (sc->clk != NULL) 345296936Smmel clk_release(sc->clk); 346296936Smmel if (sc->reset != NULL) 347296936Smmel hwreset_release(sc->reset); 348296936Smmel if (sc->mem_res != NULL) 349296936Smmel bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 350296936Smmel 351296936Smmel return (bus_generic_detach(dev)); 352296936Smmel} 353296936Smmel 354296936Smmelstatic device_method_t tegra_efuse_methods[] = { 355296936Smmel /* Device interface */ 356296936Smmel DEVMETHOD(device_probe, tegra_efuse_probe), 357296936Smmel DEVMETHOD(device_attach, tegra_efuse_attach), 358296936Smmel DEVMETHOD(device_detach, tegra_efuse_detach), 359296936Smmel 360296936Smmel DEVMETHOD_END 361296936Smmel}; 362296936Smmel 363308335Smmelstatic devclass_t tegra_efuse_devclass; 364308335Smmelstatic DEFINE_CLASS_0(efuse, tegra_efuse_driver, tegra_efuse_methods, 365296936Smmel sizeof(struct tegra_efuse_softc)); 366296936SmmelEARLY_DRIVER_MODULE(tegra_efuse, simplebus, tegra_efuse_driver, 367308335Smmel tegra_efuse_devclass, NULL, NULL, BUS_PASS_TIMER); 368