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