1 /*- 2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 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 * $FreeBSD$ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/bus.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/malloc.h> 35 #include <sys/rman.h> 36 37 #include <machine/bus.h> 38 39 #include <dev/extres/clk/clk.h> 40 #include <dev/extres/hwreset/hwreset.h> 41 #include <dev/fdt/fdt_common.h> 42 #include <dev/ofw/ofw_bus.h> 43 #include <dev/ofw/ofw_bus_subr.h> 44 45 #include <arm/nvidia/tegra_pmc.h> 46 47 #define PMC_CNTRL 0x000 48 #define PMC_CNTRL_CPUPWRGOOD_SEL_MASK (0x3 << 20) 49 #define PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT 20 50 #define PMC_CNTRL_CPUPWRGOOD_EN (1 << 19) 51 #define PMC_CNTRL_FUSE_OVERRIDE (1 << 18) 52 #define PMC_CNTRL_INTR_POLARITY (1 << 17) 53 #define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) 54 #define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) 55 #define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14) 56 #define PMC_CNTRL_AOINIT (1 << 13) 57 #define PMC_CNTRL_PWRGATE_DIS (1 << 12) 58 #define PMC_CNTRL_SYSCLK_OE (1 << 11) 59 #define PMC_CNTRL_SYSCLK_POLARITY (1 << 10) 60 #define PMC_CNTRL_PWRREQ_OE (1 << 9) 61 #define PMC_CNTRL_PWRREQ_POLARITY (1 << 8) 62 #define PMC_CNTRL_BLINK_EN (1 << 7) 63 #define PMC_CNTRL_GLITCHDET_DIS (1 << 6) 64 #define PMC_CNTRL_LATCHWAKE_EN (1 << 5) 65 #define PMC_CNTRL_MAIN_RST (1 << 4) 66 #define PMC_CNTRL_KBC_RST (1 << 3) 67 #define PMC_CNTRL_RTC_RST (1 << 2) 68 #define PMC_CNTRL_RTC_CLK_DIS (1 << 1) 69 #define PMC_CNTRL_KBC_CLK_DIS (1 << 0) 70 71 #define PMC_DPD_SAMPLE 0x020 72 73 #define PMC_CLAMP_STATUS 0x02C 74 #define PMC_CLAMP_STATUS_PARTID(x) (1 << ((x) & 0x1F)) 75 76 #define PMC_PWRGATE_TOGGLE 0x030 77 #define PMC_PWRGATE_TOGGLE_START (1 << 8) 78 #define PMC_PWRGATE_TOGGLE_PARTID(x) (((x) & 0x1F) << 0) 79 80 #define PMC_REMOVE_CLAMPING_CMD 0x034 81 #define PMC_REMOVE_CLAMPING_CMD_PARTID(x) (1 << ((x) & 0x1F)) 82 83 #define PMC_PWRGATE_STATUS 0x038 84 #define PMC_PWRGATE_STATUS_PARTID(x) (1 << ((x) & 0x1F)) 85 86 #define PMC_SCRATCH0 0x050 87 #define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) 88 #define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) 89 #define PMC_SCRATCH0_MODE_RCM (1 << 1) 90 #define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ 91 PMC_SCRATCH0_MODE_BOOTLOADER | \ 92 PMC_SCRATCH0_MODE_RCM) 93 94 #define PMC_CPUPWRGOOD_TIMER 0x0c8 95 #define PMC_CPUPWROFF_TIMER 0x0cc 96 97 #define PMC_SCRATCH41 0x140 98 99 #define PMC_SENSOR_CTRL 0x1b0 100 #define PMC_SENSOR_CTRL_BLOCK_SCRATCH_WRITE (1 << 2) 101 #define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) 102 #define PMC_SENSOR_CTRL_ENABLE_PG (1 << 0) 103 104 #define PMC_IO_DPD_REQ 0x1b8 105 #define PMC_IO_DPD_REQ_CODE_IDLE (0 << 30) 106 #define PMC_IO_DPD_REQ_CODE_OFF (1 << 30) 107 #define PMC_IO_DPD_REQ_CODE_ON (2 << 30) 108 #define PMC_IO_DPD_REQ_CODE_MASK (3 << 30) 109 110 #define PMC_IO_DPD_STATUS 0x1bc 111 #define PMC_IO_DPD_STATUS_HDMI (1 << 28) 112 #define PMC_IO_DPD2_REQ 0x1c0 113 #define PMC_IO_DPD2_STATUS 0x1c4 114 #define PMC_IO_DPD2_STATUS_HV (1 << 6) 115 #define PMC_SEL_DPD_TIM 0x1c8 116 117 #define PMC_SCRATCH54 0x258 118 #define PMC_SCRATCH54_DATA_SHIFT 8 119 #define PMC_SCRATCH54_ADDR_SHIFT 0 120 121 #define PMC_SCRATCH55 0x25c 122 #define PMC_SCRATCH55_RST_ENABLE (1 << 31) 123 #define PMC_SCRATCH55_CNTRL_TYPE (1 << 30) 124 #define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 125 #define PMC_SCRATCH55_CNTRL_ID_MASK 0x07 126 #define PMC_SCRATCH55_PINMUX_SHIFT 24 127 #define PMC_SCRATCH55_PINMUX_MASK 0x07 128 #define PMC_SCRATCH55_CHECKSUM_SHIFT 16 129 #define PMC_SCRATCH55_CHECKSUM_MASK 0xFF 130 #define PMC_SCRATCH55_16BITOP (1 << 15) 131 #define PMC_SCRATCH55_I2CSLV1_SHIFT 0 132 #define PMC_SCRATCH55_I2CSLV1_MASK 0x7F 133 134 #define PMC_GPU_RG_CNTRL 0x2d4 135 136 #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) 137 #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) 138 139 #define PMC_LOCK(_sc) mtx_lock(&(_sc)->mtx) 140 #define PMC_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 141 #define PMC_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \ 142 device_get_nameunit(_sc->dev), "tegra124_pmc", MTX_DEF) 143 #define PMC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx); 144 #define PMC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED); 145 #define PMC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED); 146 147 struct tegra124_pmc_softc { 148 device_t dev; 149 struct resource *mem_res; 150 clk_t clk; 151 struct mtx mtx; 152 153 uint32_t rate; 154 enum tegra_suspend_mode suspend_mode; 155 uint32_t cpu_good_time; 156 uint32_t cpu_off_time; 157 uint32_t core_osc_time; 158 uint32_t core_pmu_time; 159 uint32_t core_off_time; 160 int corereq_high; 161 int sysclkreq_high; 162 int combined_req; 163 int cpu_pwr_good_en; 164 uint32_t lp0_vec_phys; 165 uint32_t lp0_vec_size; 166 }; 167 168 static struct ofw_compat_data compat_data[] = { 169 {"nvidia,tegra124-pmc", 1}, 170 {NULL, 0}, 171 }; 172 173 static struct tegra124_pmc_softc *pmc_sc; 174 175 static inline struct tegra124_pmc_softc * 176 tegra124_pmc_get_sc(void) 177 { 178 if (pmc_sc == NULL) 179 panic("To early call to Tegra PMC driver.\n"); 180 return (pmc_sc); 181 } 182 183 static int 184 tegra124_pmc_set_powergate(struct tegra124_pmc_softc *sc, 185 enum tegra_powergate_id id, int ena) 186 { 187 uint32_t reg; 188 int i; 189 190 PMC_LOCK(sc); 191 192 reg = RD4(sc, PMC_PWRGATE_STATUS) & PMC_PWRGATE_STATUS_PARTID(id); 193 if (((reg != 0) && ena) || ((reg == 0) && !ena)) { 194 PMC_UNLOCK(sc); 195 return (0); 196 } 197 198 for (i = 100; i > 0; i--) { 199 reg = RD4(sc, PMC_PWRGATE_TOGGLE); 200 if ((reg & PMC_PWRGATE_TOGGLE_START) == 0) 201 break; 202 DELAY(1); 203 } 204 if (i <= 0) 205 device_printf(sc->dev, 206 "Timeout when waiting for TOGGLE_START\n"); 207 208 WR4(sc, PMC_PWRGATE_TOGGLE, 209 PMC_PWRGATE_TOGGLE_START | PMC_PWRGATE_TOGGLE_PARTID(id)); 210 211 for (i = 100; i > 0; i--) { 212 reg = RD4(sc, PMC_PWRGATE_TOGGLE); 213 if ((reg & PMC_PWRGATE_TOGGLE_START) == 0) 214 break; 215 DELAY(1); 216 } 217 if (i <= 0) 218 device_printf(sc->dev, 219 "Timeout when waiting for TOGGLE_START\n"); 220 PMC_UNLOCK(sc); 221 return (0); 222 } 223 224 int 225 tegra_powergate_remove_clamping(enum tegra_powergate_id id) 226 { 227 struct tegra124_pmc_softc *sc; 228 uint32_t reg; 229 enum tegra_powergate_id swid; 230 int i; 231 232 sc = tegra124_pmc_get_sc(); 233 234 if (id == TEGRA_POWERGATE_3D) { 235 WR4(sc, PMC_GPU_RG_CNTRL, 0); 236 return (0); 237 } 238 239 reg = RD4(sc, PMC_PWRGATE_STATUS); 240 if ((reg & PMC_PWRGATE_STATUS_PARTID(id)) == 0) 241 panic("Attempt to remove clamping for unpowered partition.\n"); 242 243 if (id == TEGRA_POWERGATE_PCX) 244 swid = TEGRA_POWERGATE_VDE; 245 else if (id == TEGRA_POWERGATE_VDE) 246 swid = TEGRA_POWERGATE_PCX; 247 else 248 swid = id; 249 WR4(sc, PMC_REMOVE_CLAMPING_CMD, PMC_REMOVE_CLAMPING_CMD_PARTID(swid)); 250 251 for (i = 100; i > 0; i--) { 252 reg = RD4(sc, PMC_REMOVE_CLAMPING_CMD); 253 if ((reg & PMC_REMOVE_CLAMPING_CMD_PARTID(swid)) == 0) 254 break; 255 DELAY(1); 256 } 257 if (i <= 0) 258 device_printf(sc->dev, "Timeout when remove clamping\n"); 259 260 reg = RD4(sc, PMC_CLAMP_STATUS); 261 if ((reg & PMC_CLAMP_STATUS_PARTID(id)) != 0) 262 panic("Cannot remove clamping\n"); 263 264 return (0); 265 } 266 267 int 268 tegra_powergate_is_powered(enum tegra_powergate_id id) 269 { 270 struct tegra124_pmc_softc *sc; 271 uint32_t reg; 272 273 sc = tegra124_pmc_get_sc(); 274 275 reg = RD4(sc, PMC_PWRGATE_STATUS); 276 return ((reg & PMC_PWRGATE_STATUS_PARTID(id)) ? 1 : 0); 277 } 278 279 int 280 tegra_powergate_power_on(enum tegra_powergate_id id) 281 { 282 struct tegra124_pmc_softc *sc; 283 int rv, i; 284 285 sc = tegra124_pmc_get_sc(); 286 287 rv = tegra124_pmc_set_powergate(sc, id, 1); 288 if (rv != 0) { 289 device_printf(sc->dev, "Cannot set powergate: %d\n", id); 290 return (rv); 291 } 292 293 for (i = 100; i > 0; i--) { 294 if (tegra_powergate_is_powered(id)) 295 break; 296 DELAY(1); 297 } 298 if (i <= 0) 299 device_printf(sc->dev, "Timeout when waiting on power up\n"); 300 301 return (rv); 302 } 303 304 int 305 tegra_powergate_power_off(enum tegra_powergate_id id) 306 { 307 struct tegra124_pmc_softc *sc; 308 int rv, i; 309 310 sc = tegra124_pmc_get_sc(); 311 312 rv = tegra124_pmc_set_powergate(sc, id, 0); 313 if (rv != 0) { 314 device_printf(sc->dev, "Cannot set powergate: %d\n", id); 315 return (rv); 316 } 317 for (i = 100; i > 0; i--) { 318 if (!tegra_powergate_is_powered(id)) 319 break; 320 DELAY(1); 321 } 322 if (i <= 0) 323 device_printf(sc->dev, "Timeout when waiting on power off\n"); 324 325 return (rv); 326 } 327 328 int 329 tegra_powergate_sequence_power_up(enum tegra_powergate_id id, clk_t clk, 330 hwreset_t rst) 331 { 332 struct tegra124_pmc_softc *sc; 333 int rv; 334 335 sc = tegra124_pmc_get_sc(); 336 337 rv = hwreset_assert(rst); 338 if (rv != 0) { 339 device_printf(sc->dev, "Cannot assert reset\n"); 340 return (rv); 341 } 342 343 rv = clk_stop(clk); 344 if (rv != 0) { 345 device_printf(sc->dev, "Cannot stop clock\n"); 346 goto clk_fail; 347 } 348 349 rv = tegra_powergate_power_on(id); 350 if (rv != 0) { 351 device_printf(sc->dev, "Cannot power on powergate\n"); 352 goto clk_fail; 353 } 354 355 rv = clk_enable(clk); 356 if (rv != 0) { 357 device_printf(sc->dev, "Cannot enable clock\n"); 358 goto clk_fail; 359 } 360 DELAY(20); 361 362 rv = tegra_powergate_remove_clamping(id); 363 if (rv != 0) { 364 device_printf(sc->dev, "Cannot remove clamping\n"); 365 goto fail; 366 } 367 rv = hwreset_deassert(rst); 368 if (rv != 0) { 369 device_printf(sc->dev, "Cannot unreset reset\n"); 370 goto fail; 371 } 372 return 0; 373 374 fail: 375 clk_disable(clk); 376 clk_fail: 377 hwreset_assert(rst); 378 tegra_powergate_power_off(id); 379 return (rv); 380 } 381 382 static int 383 tegra124_pmc_parse_fdt(struct tegra124_pmc_softc *sc, phandle_t node) 384 { 385 int rv; 386 uint32_t tmp; 387 uint32_t tmparr[2]; 388 389 rv = OF_getencprop(node, "nvidia,suspend-mode", &tmp, sizeof(tmp)); 390 if (rv > 0) { 391 switch (tmp) { 392 case 0: 393 sc->suspend_mode = TEGRA_SUSPEND_LP0; 394 break; 395 396 case 1: 397 sc->suspend_mode = TEGRA_SUSPEND_LP1; 398 break; 399 400 case 2: 401 sc->suspend_mode = TEGRA_SUSPEND_LP2; 402 break; 403 404 default: 405 sc->suspend_mode = TEGRA_SUSPEND_NONE; 406 break; 407 } 408 } 409 410 rv = OF_getencprop(node, "nvidia,cpu-pwr-good-time", &tmp, sizeof(tmp)); 411 if (rv > 0) { 412 sc->cpu_good_time = tmp; 413 sc->suspend_mode = TEGRA_SUSPEND_NONE; 414 } 415 416 rv = OF_getencprop(node, "nvidia,cpu-pwr-off-time", &tmp, sizeof(tmp)); 417 if (rv > 0) { 418 sc->cpu_off_time = tmp; 419 sc->suspend_mode = TEGRA_SUSPEND_NONE; 420 } 421 422 rv = OF_getencprop(node, "nvidia,core-pwr-good-time", tmparr, 423 sizeof(tmparr)); 424 if (rv == sizeof(tmparr)) { 425 sc->core_osc_time = tmparr[0]; 426 sc->core_pmu_time = tmparr[1]; 427 sc->suspend_mode = TEGRA_SUSPEND_NONE; 428 } 429 430 rv = OF_getencprop(node, "nvidia,core-pwr-off-time", &tmp, sizeof(tmp)); 431 if (rv > 0) { 432 sc->core_off_time = tmp; 433 sc->suspend_mode = TEGRA_SUSPEND_NONE; 434 } 435 436 sc->corereq_high = 437 OF_hasprop(node, "nvidia,core-power-req-active-high"); 438 sc->sysclkreq_high = 439 OF_hasprop(node, "nvidia,sys-clock-req-active-high"); 440 sc->combined_req = 441 OF_hasprop(node, "nvidia,combined-power-req"); 442 sc->cpu_pwr_good_en = 443 OF_hasprop(node, "nvidia,cpu-pwr-good-en"); 444 445 rv = OF_getencprop(node, "nvidia,lp0-vec", tmparr, sizeof(tmparr)); 446 if (rv == sizeof(tmparr)) { 447 448 sc->lp0_vec_phys = tmparr[0]; 449 sc->core_pmu_time = tmparr[1]; 450 sc->lp0_vec_size = TEGRA_SUSPEND_NONE; 451 if (sc->suspend_mode == TEGRA_SUSPEND_LP0) 452 sc->suspend_mode = TEGRA_SUSPEND_LP1; 453 } 454 return 0; 455 } 456 457 static int 458 tegra124_pmc_probe(device_t dev) 459 { 460 461 if (!ofw_bus_status_okay(dev)) 462 return (ENXIO); 463 464 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 465 return (ENXIO); 466 467 device_set_desc(dev, "Tegra PMC"); 468 return (BUS_PROBE_DEFAULT); 469 } 470 471 static int 472 tegra124_pmc_detach(device_t dev) 473 { 474 475 /* This device is always present. */ 476 return (EBUSY); 477 } 478 479 static int 480 tegra124_pmc_attach(device_t dev) 481 { 482 struct tegra124_pmc_softc *sc; 483 int rid, rv; 484 uint32_t reg; 485 phandle_t node; 486 487 sc = device_get_softc(dev); 488 sc->dev = dev; 489 node = ofw_bus_get_node(dev); 490 491 rv = tegra124_pmc_parse_fdt(sc, node); 492 if (rv != 0) { 493 device_printf(sc->dev, "Cannot parse FDT data\n"); 494 return (rv); 495 } 496 497 rv = clk_get_by_ofw_name(sc->dev, "pclk", &sc->clk); 498 if (rv != 0) { 499 device_printf(sc->dev, "Cannot get \"pclk\" clock\n"); 500 return (ENXIO); 501 } 502 503 rid = 0; 504 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 505 RF_ACTIVE); 506 if (sc->mem_res == NULL) { 507 device_printf(dev, "Cannot allocate memory resources\n"); 508 return (ENXIO); 509 } 510 511 PMC_LOCK_INIT(sc); 512 513 /* Enable CPU power request. */ 514 reg = RD4(sc, PMC_CNTRL); 515 reg |= PMC_CNTRL_CPU_PWRREQ_OE; 516 WR4(sc, PMC_CNTRL, reg); 517 518 /* Set sysclk output polarity */ 519 reg = RD4(sc, PMC_CNTRL); 520 if (sc->sysclkreq_high) 521 reg &= ~PMC_CNTRL_SYSCLK_POLARITY; 522 else 523 reg |= PMC_CNTRL_SYSCLK_POLARITY; 524 WR4(sc, PMC_CNTRL, reg); 525 526 /* Enable sysclk request. */ 527 reg = RD4(sc, PMC_CNTRL); 528 reg |= PMC_CNTRL_SYSCLK_OE; 529 WR4(sc, PMC_CNTRL, reg); 530 531 /* 532 * Remove HDMI from deep power down mode. 533 * XXX mote this to HDMI driver 534 */ 535 reg = RD4(sc, PMC_IO_DPD_STATUS); 536 reg &= ~ PMC_IO_DPD_STATUS_HDMI; 537 WR4(sc, PMC_IO_DPD_STATUS, reg); 538 539 reg = RD4(sc, PMC_IO_DPD2_STATUS); 540 reg &= ~ PMC_IO_DPD2_STATUS_HV; 541 WR4(sc, PMC_IO_DPD2_STATUS, reg); 542 543 if (pmc_sc != NULL) 544 panic("tegra124_pmc: double driver attach"); 545 pmc_sc = sc; 546 return (0); 547 } 548 549 static device_method_t tegra124_pmc_methods[] = { 550 /* Device interface */ 551 DEVMETHOD(device_probe, tegra124_pmc_probe), 552 DEVMETHOD(device_attach, tegra124_pmc_attach), 553 DEVMETHOD(device_detach, tegra124_pmc_detach), 554 555 DEVMETHOD_END 556 }; 557 558 static driver_t tegra124_pmc_driver = { 559 "tegra124_pmc", 560 tegra124_pmc_methods, 561 sizeof(struct tegra124_pmc_softc), 562 }; 563 564 static devclass_t tegra124_pmc_devclass; 565 EARLY_DRIVER_MODULE(tegra124_pmc, simplebus, tegra124_pmc_driver, 566 tegra124_pmc_devclass, 0, 0, 70); 567