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