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/ofw/ofw_bus.h> 48 #include <dev/ofw/ofw_bus_subr.h> 49 50 #include <arm/nvidia/tegra_efuse.h> 51 52 #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_sc)->fuse_begin + (_r)) 53 54 static struct ofw_compat_data compat_data[] = { 55 {"nvidia,tegra124-efuse", 1}, 56 {NULL, 0} 57 }; 58 59 struct tegra_efuse_softc { 60 device_t dev; 61 struct resource *mem_res; 62 63 int fuse_begin; 64 clk_t clk; 65 hwreset_t reset; 66 }; 67 struct tegra_efuse_softc *dev_sc; 68 69 struct tegra_sku_info tegra_sku_info; 70 static char *tegra_rev_name[] = { 71 [TEGRA_REVISION_UNKNOWN] = "unknown", 72 [TEGRA_REVISION_A01] = "A01", 73 [TEGRA_REVISION_A02] = "A02", 74 [TEGRA_REVISION_A03] = "A03", 75 [TEGRA_REVISION_A03p] = "A03 prime", 76 [TEGRA_REVISION_A04] = "A04", 77 }; 78 79 /* Tegra30 and later */ 80 #define FUSE_VENDOR_CODE 0x100 81 #define FUSE_FAB_CODE 0x104 82 #define FUSE_LOT_CODE_0 0x108 83 #define FUSE_LOT_CODE_1 0x10c 84 #define FUSE_WAFER_ID 0x110 85 #define FUSE_X_COORDINATE 0x114 86 #define FUSE_Y_COORDINATE 0x118 87 88 /* ---------------------- Tegra 124 specific code & data --------------- */ 89 #define TEGRA124_FUSE_BEGIN 0x100 90 91 #define TEGRA124_CPU_PROCESS_CORNERS 2 92 #define TEGRA124_GPU_PROCESS_CORNERS 2 93 #define TEGRA124_SOC_PROCESS_CORNERS 2 94 95 #define TEGRA124_FUSE_SKU_INFO 0x10 96 #define TEGRA124_FUSE_CPU_SPEEDO_0 0x14 97 #define TEGRA124_FUSE_CPU_IDDQ 0x18 98 #define TEGRA124_FUSE_FT_REV 0x28 99 #define TEGRA124_FUSE_CPU_SPEEDO_1 0x2c 100 #define TEGRA124_FUSE_CPU_SPEEDO_2 0x30 101 #define TEGRA124_FUSE_SOC_SPEEDO_0 0x34 102 #define TEGRA124_FUSE_SOC_SPEEDO_1 0x38 103 #define TEGRA124_FUSE_SOC_SPEEDO_2 0x3c 104 #define TEGRA124_FUSE_SOC_IDDQ 0x40 105 #define TEGRA124_FUSE_GPU_IDDQ 0x128 106 107 enum { 108 TEGRA124_THRESHOLD_INDEX_0, 109 TEGRA124_THRESHOLD_INDEX_1, 110 TEGRA124_THRESHOLD_INDEX_COUNT, 111 }; 112 113 static uint32_t tegra124_cpu_process_speedos[][TEGRA124_CPU_PROCESS_CORNERS] = 114 { 115 {2190, UINT_MAX}, 116 {0, UINT_MAX}, 117 }; 118 119 static uint32_t tegra124_gpu_process_speedos[][TEGRA124_GPU_PROCESS_CORNERS] = 120 { 121 {1965, UINT_MAX}, 122 {0, UINT_MAX}, 123 }; 124 125 static uint32_t tegra124_soc_process_speedos[][TEGRA124_SOC_PROCESS_CORNERS] = 126 { 127 {2101, UINT_MAX}, 128 {0, UINT_MAX}, 129 }; 130 131 static void 132 tegra124_rev_sku_to_speedo_ids(struct tegra_efuse_softc *sc, 133 struct tegra_sku_info *sku, int *threshold) 134 { 135 136 /* Assign to default */ 137 sku->cpu_speedo_id = 0; 138 sku->soc_speedo_id = 0; 139 sku->gpu_speedo_id = 0; 140 *threshold = TEGRA124_THRESHOLD_INDEX_0; 141 142 switch (sku->sku_id) { 143 case 0x00: /* Eng sku */ 144 case 0x0F: 145 case 0x23: 146 /* Using the default */ 147 break; 148 case 0x83: 149 sku->cpu_speedo_id = 2; 150 break; 151 152 case 0x1F: 153 case 0x87: 154 case 0x27: 155 sku->cpu_speedo_id = 2; 156 sku->soc_speedo_id = 0; 157 sku->gpu_speedo_id = 1; 158 *threshold = TEGRA124_THRESHOLD_INDEX_0; 159 break; 160 case 0x81: 161 case 0x21: 162 case 0x07: 163 sku->cpu_speedo_id = 1; 164 sku->soc_speedo_id = 1; 165 sku->gpu_speedo_id = 1; 166 *threshold = TEGRA124_THRESHOLD_INDEX_1; 167 break; 168 case 0x49: 169 case 0x4A: 170 case 0x48: 171 sku->cpu_speedo_id = 4; 172 sku->soc_speedo_id = 2; 173 sku->gpu_speedo_id = 3; 174 *threshold = TEGRA124_THRESHOLD_INDEX_1; 175 break; 176 default: 177 device_printf(sc->dev, " Unknown SKU ID %d\n", sku->sku_id); 178 break; 179 } 180 } 181 182 static void 183 tegra124_init_speedo(struct tegra_efuse_softc *sc, struct tegra_sku_info *sku) 184 { 185 int i, threshold; 186 187 sku->sku_id = RD4(sc, TEGRA124_FUSE_SKU_INFO); 188 sku->soc_iddq_value = RD4(sc, TEGRA124_FUSE_SOC_IDDQ); 189 sku->cpu_iddq_value = RD4(sc, TEGRA124_FUSE_CPU_IDDQ); 190 sku->gpu_iddq_value = RD4(sc, TEGRA124_FUSE_GPU_IDDQ); 191 sku->soc_speedo_value = RD4(sc, TEGRA124_FUSE_SOC_SPEEDO_0); 192 sku->cpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_0); 193 sku->gpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_2); 194 195 if (sku->cpu_speedo_value == 0) { 196 device_printf(sc->dev, "CPU Speedo value is not fused.\n"); 197 return; 198 } 199 200 tegra124_rev_sku_to_speedo_ids(sc, sku, &threshold); 201 202 for (i = 0; i < TEGRA124_SOC_PROCESS_CORNERS; i++) { 203 if (sku->soc_speedo_value < 204 tegra124_soc_process_speedos[threshold][i]) 205 break; 206 } 207 sku->soc_process_id = i; 208 209 for (i = 0; i < TEGRA124_CPU_PROCESS_CORNERS; i++) { 210 if (sku->cpu_speedo_value < 211 tegra124_cpu_process_speedos[threshold][i]) 212 break; 213 } 214 sku->cpu_process_id = i; 215 216 for (i = 0; i < TEGRA124_GPU_PROCESS_CORNERS; i++) { 217 if (sku->gpu_speedo_value < 218 tegra124_gpu_process_speedos[threshold][i]) 219 break; 220 } 221 sku->gpu_process_id = i; 222 223 } 224 225 /* ----------------- End of Tegra 124 specific code & data --------------- */ 226 227 uint32_t 228 tegra_fuse_read_4(int addr) { 229 if (dev_sc == NULL) 230 panic("tegra_fuse_read_4 called too early"); 231 return (RD4(dev_sc, addr)); 232 } 233 234 static void 235 tegra_efuse_dump_sku(void) 236 { 237 printf(" TEGRA SKU Info:\n"); 238 printf(" chip_id: %u\n", tegra_sku_info.chip_id); 239 printf(" sku_id: %u\n", tegra_sku_info.sku_id); 240 printf(" cpu_process_id: %u\n", tegra_sku_info.cpu_process_id); 241 printf(" cpu_speedo_id: %u\n", tegra_sku_info.cpu_speedo_id); 242 printf(" cpu_speedo_value: %u\n", tegra_sku_info.cpu_speedo_value); 243 printf(" cpu_iddq_value: %u\n", tegra_sku_info.cpu_iddq_value); 244 printf(" soc_process_id: %u\n", tegra_sku_info.soc_process_id); 245 printf(" soc_speedo_id: %u\n", tegra_sku_info.soc_speedo_id); 246 printf(" soc_speedo_value: %u\n", tegra_sku_info.soc_speedo_value); 247 printf(" soc_iddq_value: %u\n", tegra_sku_info.soc_iddq_value); 248 printf(" gpu_process_id: %u\n", tegra_sku_info.gpu_process_id); 249 printf(" gpu_speedo_id: %u\n", tegra_sku_info.gpu_speedo_id); 250 printf(" gpu_speedo_value: %u\n", tegra_sku_info.gpu_speedo_value); 251 printf(" gpu_iddq_value: %u\n", tegra_sku_info.gpu_iddq_value); 252 printf(" revision: %s\n", tegra_rev_name[tegra_sku_info.revision]); 253 } 254 255 static int 256 tegra_efuse_probe(device_t dev) 257 { 258 if (!ofw_bus_status_okay(dev)) 259 return (ENXIO); 260 261 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 262 return (ENXIO); 263 264 return (BUS_PROBE_DEFAULT); 265 } 266 267 static int 268 tegra_efuse_attach(device_t dev) 269 { 270 int rv, rid; 271 phandle_t node; 272 struct tegra_efuse_softc *sc; 273 274 sc = device_get_softc(dev); 275 sc->dev = dev; 276 node = ofw_bus_get_node(dev); 277 278 /* Get the memory resource for the register mapping. */ 279 rid = 0; 280 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 281 RF_ACTIVE); 282 if (sc->mem_res == NULL) { 283 device_printf(dev, "Cannot map registers.\n"); 284 rv = ENXIO; 285 goto fail; 286 } 287 288 /* OFW resources. */ 289 rv = clk_get_by_ofw_name(dev, 0, "fuse", &sc->clk); 290 if (rv != 0) { 291 device_printf(dev, "Cannot get fuse clock: %d\n", rv); 292 goto fail; 293 } 294 rv = clk_enable(sc->clk); 295 if (rv != 0) { 296 device_printf(dev, "Cannot enable clock: %d\n", rv); 297 goto fail; 298 } 299 rv = hwreset_get_by_ofw_name(sc->dev, 0, "fuse", &sc->reset); 300 if (rv != 0) { 301 device_printf(dev, "Cannot get fuse reset\n"); 302 goto fail; 303 } 304 rv = hwreset_deassert(sc->reset); 305 if (rv != 0) { 306 device_printf(sc->dev, "Cannot clear reset\n"); 307 goto fail; 308 } 309 310 /* Tegra124 specific init. */ 311 sc->fuse_begin = TEGRA124_FUSE_BEGIN; 312 tegra124_init_speedo(sc, &tegra_sku_info); 313 314 dev_sc = sc; 315 316 if (bootverbose) 317 tegra_efuse_dump_sku(); 318 return (bus_generic_attach(dev)); 319 320 fail: 321 dev_sc = NULL; 322 if (sc->clk != NULL) 323 clk_release(sc->clk); 324 if (sc->reset != NULL) 325 hwreset_release(sc->reset); 326 if (sc->mem_res != NULL) 327 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 328 329 return (rv); 330 } 331 332 static int 333 tegra_efuse_detach(device_t dev) 334 { 335 struct tegra_efuse_softc *sc; 336 337 sc = device_get_softc(dev); 338 dev_sc = NULL; 339 if (sc->clk != NULL) 340 clk_release(sc->clk); 341 if (sc->reset != NULL) 342 hwreset_release(sc->reset); 343 if (sc->mem_res != NULL) 344 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 345 346 return (bus_generic_detach(dev)); 347 } 348 349 static device_method_t tegra_efuse_methods[] = { 350 /* Device interface */ 351 DEVMETHOD(device_probe, tegra_efuse_probe), 352 DEVMETHOD(device_attach, tegra_efuse_attach), 353 DEVMETHOD(device_detach, tegra_efuse_detach), 354 355 DEVMETHOD_END 356 }; 357 358 static devclass_t tegra_efuse_devclass; 359 static DEFINE_CLASS_0(efuse, tegra_efuse_driver, tegra_efuse_methods, 360 sizeof(struct tegra_efuse_softc)); 361 EARLY_DRIVER_MODULE(tegra_efuse, simplebus, tegra_efuse_driver, 362 tegra_efuse_devclass, NULL, NULL, BUS_PASS_TIMER); 363