1 /*- 2 * Copyright (c) 2015 Michal Meloun 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/bus.h> 33 #include <sys/clock.h> 34 #include <sys/kernel.h> 35 #include <sys/limits.h> 36 #include <sys/lock.h> 37 #include <sys/mutex.h> 38 #include <sys/module.h> 39 #include <sys/resource.h> 40 #include <sys/rman.h> 41 42 #include <machine/bus.h> 43 #include <machine/resource.h> 44 45 #include <dev/extres/clk/clk.h> 46 #include <dev/extres/hwreset/hwreset.h> 47 #include <dev/fdt/fdt_common.h> 48 #include <dev/ofw/ofw_bus.h> 49 #include <dev/ofw/ofw_bus_subr.h> 50 51 #include <arm/nvidia/tegra_efuse.h> 52 53 54 #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_sc)->fuse_begin + (_r)) 55 56 static struct ofw_compat_data compat_data[] = { 57 {"nvidia,tegra124-efuse", 1}, 58 {NULL, 0} 59 }; 60 61 struct tegra_efuse_softc { 62 device_t dev; 63 struct resource *mem_res; 64 65 int fuse_begin; 66 clk_t clk; 67 hwreset_t reset; 68 }; 69 struct tegra_efuse_softc *dev_sc; 70 71 struct tegra_sku_info tegra_sku_info; 72 static char *tegra_rev_name[] = { 73 [TEGRA_REVISION_UNKNOWN] = "unknown", 74 [TEGRA_REVISION_A01] = "A01", 75 [TEGRA_REVISION_A02] = "A02", 76 [TEGRA_REVISION_A03] = "A03", 77 [TEGRA_REVISION_A03p] = "A03 prime", 78 [TEGRA_REVISION_A04] = "A04", 79 }; 80 81 /* Tegra30 and later */ 82 #define FUSE_VENDOR_CODE 0x100 83 #define FUSE_FAB_CODE 0x104 84 #define FUSE_LOT_CODE_0 0x108 85 #define FUSE_LOT_CODE_1 0x10c 86 #define FUSE_WAFER_ID 0x110 87 #define FUSE_X_COORDINATE 0x114 88 #define FUSE_Y_COORDINATE 0x118 89 90 /* ---------------------- Tegra 124 specific code & data --------------- */ 91 #define TEGRA124_FUSE_BEGIN 0x100 92 93 #define TEGRA124_CPU_PROCESS_CORNERS 2 94 #define TEGRA124_GPU_PROCESS_CORNERS 2 95 #define TEGRA124_SOC_PROCESS_CORNERS 2 96 97 #define TEGRA124_FUSE_SKU_INFO 0x10 98 #define TEGRA124_FUSE_CPU_SPEEDO_0 0x14 99 #define TEGRA124_FUSE_CPU_IDDQ 0x18 100 #define TEGRA124_FUSE_FT_REV 0x28 101 #define TEGRA124_FUSE_CPU_SPEEDO_1 0x2c 102 #define TEGRA124_FUSE_CPU_SPEEDO_2 0x30 103 #define TEGRA124_FUSE_SOC_SPEEDO_0 0x34 104 #define TEGRA124_FUSE_SOC_SPEEDO_1 0x38 105 #define TEGRA124_FUSE_SOC_SPEEDO_2 0x3c 106 #define TEGRA124_FUSE_SOC_IDDQ 0x40 107 #define TEGRA124_FUSE_GPU_IDDQ 0x128 108 109 enum { 110 TEGRA124_THRESHOLD_INDEX_0, 111 TEGRA124_THRESHOLD_INDEX_1, 112 TEGRA124_THRESHOLD_INDEX_COUNT, 113 }; 114 115 static uint32_t tegra124_cpu_process_speedos[][TEGRA124_CPU_PROCESS_CORNERS] = 116 { 117 {2190, UINT_MAX}, 118 {0, UINT_MAX}, 119 }; 120 121 static uint32_t tegra124_gpu_process_speedos[][TEGRA124_GPU_PROCESS_CORNERS] = 122 { 123 {1965, UINT_MAX}, 124 {0, UINT_MAX}, 125 }; 126 127 static uint32_t tegra124_soc_process_speedos[][TEGRA124_SOC_PROCESS_CORNERS] = 128 { 129 {2101, UINT_MAX}, 130 {0, UINT_MAX}, 131 }; 132 133 static void 134 tegra124_rev_sku_to_speedo_ids(struct tegra_efuse_softc *sc, 135 struct tegra_sku_info *sku, int *threshold) 136 { 137 138 /* Assign to default */ 139 sku->cpu_speedo_id = 0; 140 sku->soc_speedo_id = 0; 141 sku->gpu_speedo_id = 0; 142 *threshold = TEGRA124_THRESHOLD_INDEX_0; 143 144 switch (sku->sku_id) { 145 case 0x00: /* Eng sku */ 146 case 0x0F: 147 case 0x23: 148 /* Using the default */ 149 break; 150 case 0x83: 151 sku->cpu_speedo_id = 2; 152 break; 153 154 case 0x1F: 155 case 0x87: 156 case 0x27: 157 sku->cpu_speedo_id = 2; 158 sku->soc_speedo_id = 0; 159 sku->gpu_speedo_id = 1; 160 *threshold = TEGRA124_THRESHOLD_INDEX_0; 161 break; 162 case 0x81: 163 case 0x21: 164 case 0x07: 165 sku->cpu_speedo_id = 1; 166 sku->soc_speedo_id = 1; 167 sku->gpu_speedo_id = 1; 168 *threshold = TEGRA124_THRESHOLD_INDEX_1; 169 break; 170 case 0x49: 171 case 0x4A: 172 case 0x48: 173 sku->cpu_speedo_id = 4; 174 sku->soc_speedo_id = 2; 175 sku->gpu_speedo_id = 3; 176 *threshold = TEGRA124_THRESHOLD_INDEX_1; 177 break; 178 default: 179 device_printf(sc->dev, " Unknown SKU ID %d\n", sku->sku_id); 180 break; 181 } 182 } 183 184 185 static void 186 tegra124_init_speedo(struct tegra_efuse_softc *sc, struct tegra_sku_info *sku) 187 { 188 int i, threshold; 189 190 sku->sku_id = RD4(sc, TEGRA124_FUSE_SKU_INFO); 191 sku->soc_iddq_value = RD4(sc, TEGRA124_FUSE_SOC_IDDQ); 192 sku->cpu_iddq_value = RD4(sc, TEGRA124_FUSE_CPU_IDDQ); 193 sku->gpu_iddq_value = RD4(sc, TEGRA124_FUSE_GPU_IDDQ); 194 sku->soc_speedo_value = RD4(sc, TEGRA124_FUSE_SOC_SPEEDO_0); 195 sku->cpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_0); 196 sku->gpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_2); 197 198 if (sku->cpu_speedo_value == 0) { 199 device_printf(sc->dev, "CPU Speedo value is not fused.\n"); 200 return; 201 } 202 203 tegra124_rev_sku_to_speedo_ids(sc, sku, &threshold); 204 205 for (i = 0; i < TEGRA124_SOC_PROCESS_CORNERS; i++) { 206 if (sku->soc_speedo_value < 207 tegra124_soc_process_speedos[threshold][i]) 208 break; 209 } 210 sku->soc_process_id = i; 211 212 for (i = 0; i < TEGRA124_CPU_PROCESS_CORNERS; i++) { 213 if (sku->cpu_speedo_value < 214 tegra124_cpu_process_speedos[threshold][i]) 215 break; 216 } 217 sku->cpu_process_id = i; 218 219 for (i = 0; i < TEGRA124_GPU_PROCESS_CORNERS; i++) { 220 if (sku->gpu_speedo_value < 221 tegra124_gpu_process_speedos[threshold][i]) 222 break; 223 } 224 sku->gpu_process_id = i; 225 226 } 227 228 /* ----------------- End of Tegra 124 specific code & data --------------- */ 229 230 uint32_t 231 tegra_fuse_read_4(int addr) { 232 233 if (dev_sc == NULL) 234 panic("tegra_fuse_read_4 called too early"); 235 return (RD4(dev_sc, addr)); 236 } 237 238 239 static void 240 tegra_efuse_dump_sku() 241 { 242 printf(" TEGRA SKU Info:\n"); 243 printf(" chip_id: %u\n", tegra_sku_info.chip_id); 244 printf(" sku_id: %u\n", tegra_sku_info.sku_id); 245 printf(" cpu_process_id: %u\n", tegra_sku_info.cpu_process_id); 246 printf(" cpu_speedo_id: %u\n", tegra_sku_info.cpu_speedo_id); 247 printf(" cpu_speedo_value: %u\n", tegra_sku_info.cpu_speedo_value); 248 printf(" cpu_iddq_value: %u\n", tegra_sku_info.cpu_iddq_value); 249 printf(" soc_process_id: %u\n", tegra_sku_info.soc_process_id); 250 printf(" soc_speedo_id: %u\n", tegra_sku_info.soc_speedo_id); 251 printf(" soc_speedo_value: %u\n", tegra_sku_info.soc_speedo_value); 252 printf(" soc_iddq_value: %u\n", tegra_sku_info.soc_iddq_value); 253 printf(" gpu_process_id: %u\n", tegra_sku_info.gpu_process_id); 254 printf(" gpu_speedo_id: %u\n", tegra_sku_info.gpu_speedo_id); 255 printf(" gpu_speedo_value: %u\n", tegra_sku_info.gpu_speedo_value); 256 printf(" gpu_iddq_value: %u\n", tegra_sku_info.gpu_iddq_value); 257 printf(" revision: %s\n", tegra_rev_name[tegra_sku_info.revision]); 258 } 259 260 static int 261 tegra_efuse_probe(device_t dev) 262 { 263 if (!ofw_bus_status_okay(dev)) 264 return (ENXIO); 265 266 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 267 return (ENXIO); 268 269 return (BUS_PROBE_DEFAULT); 270 } 271 272 static int 273 tegra_efuse_attach(device_t dev) 274 { 275 int rv, rid; 276 phandle_t node; 277 struct tegra_efuse_softc *sc; 278 279 sc = device_get_softc(dev); 280 sc->dev = dev; 281 node = ofw_bus_get_node(dev); 282 283 /* Get the memory resource for the register mapping. */ 284 rid = 0; 285 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 286 RF_ACTIVE); 287 if (sc->mem_res == NULL) { 288 device_printf(dev, "Cannot map registers.\n"); 289 rv = ENXIO; 290 goto fail; 291 } 292 293 /* OFW resources. */ 294 rv = clk_get_by_ofw_name(dev, 0, "fuse", &sc->clk); 295 if (rv != 0) { 296 device_printf(dev, "Cannot get fuse clock: %d\n", rv); 297 goto fail; 298 } 299 rv = clk_enable(sc->clk); 300 if (rv != 0) { 301 device_printf(dev, "Cannot enable clock: %d\n", rv); 302 goto fail; 303 } 304 rv = hwreset_get_by_ofw_name(sc->dev, 0, "fuse", &sc->reset); 305 if (rv != 0) { 306 device_printf(dev, "Cannot get fuse reset\n"); 307 goto fail; 308 } 309 rv = hwreset_deassert(sc->reset); 310 if (rv != 0) { 311 device_printf(sc->dev, "Cannot clear reset\n"); 312 goto fail; 313 } 314 315 /* Tegra124 specific init. */ 316 sc->fuse_begin = TEGRA124_FUSE_BEGIN; 317 tegra124_init_speedo(sc, &tegra_sku_info); 318 319 dev_sc = sc; 320 321 if (bootverbose) 322 tegra_efuse_dump_sku(); 323 return (bus_generic_attach(dev)); 324 325 fail: 326 dev_sc = NULL; 327 if (sc->clk != NULL) 328 clk_release(sc->clk); 329 if (sc->reset != NULL) 330 hwreset_release(sc->reset); 331 if (sc->mem_res != NULL) 332 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 333 334 return (rv); 335 } 336 337 static int 338 tegra_efuse_detach(device_t dev) 339 { 340 struct tegra_efuse_softc *sc; 341 342 sc = device_get_softc(dev); 343 dev_sc = NULL; 344 if (sc->clk != NULL) 345 clk_release(sc->clk); 346 if (sc->reset != NULL) 347 hwreset_release(sc->reset); 348 if (sc->mem_res != NULL) 349 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 350 351 return (bus_generic_detach(dev)); 352 } 353 354 static device_method_t tegra_efuse_methods[] = { 355 /* Device interface */ 356 DEVMETHOD(device_probe, tegra_efuse_probe), 357 DEVMETHOD(device_attach, tegra_efuse_attach), 358 DEVMETHOD(device_detach, tegra_efuse_detach), 359 360 DEVMETHOD_END 361 }; 362 363 static devclass_t tegra_efuse_devclass; 364 static DEFINE_CLASS_0(efuse, tegra_efuse_driver, tegra_efuse_methods, 365 sizeof(struct tegra_efuse_softc)); 366 EARLY_DRIVER_MODULE(tegra_efuse, simplebus, tegra_efuse_driver, 367 tegra_efuse_devclass, NULL, NULL, BUS_PASS_TIMER); 368