1*09f455dcSMasahiro Yamada /* 2*09f455dcSMasahiro Yamada * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. 3*09f455dcSMasahiro Yamada * 4*09f455dcSMasahiro Yamada * SPDX-License-Identifier: GPL-2.0 5*09f455dcSMasahiro Yamada */ 6*09f455dcSMasahiro Yamada 7*09f455dcSMasahiro Yamada #include <common.h> 8*09f455dcSMasahiro Yamada #include <errno.h> 9*09f455dcSMasahiro Yamada 10*09f455dcSMasahiro Yamada #include <asm/io.h> 11*09f455dcSMasahiro Yamada #include <asm/types.h> 12*09f455dcSMasahiro Yamada 13*09f455dcSMasahiro Yamada #include <asm/arch/powergate.h> 14*09f455dcSMasahiro Yamada #include <asm/arch/tegra.h> 15*09f455dcSMasahiro Yamada 16*09f455dcSMasahiro Yamada #define PWRGATE_TOGGLE 0x30 17*09f455dcSMasahiro Yamada #define PWRGATE_TOGGLE_START (1 << 8) 18*09f455dcSMasahiro Yamada 19*09f455dcSMasahiro Yamada #define REMOVE_CLAMPING 0x34 20*09f455dcSMasahiro Yamada 21*09f455dcSMasahiro Yamada #define PWRGATE_STATUS 0x38 22*09f455dcSMasahiro Yamada 23*09f455dcSMasahiro Yamada static int tegra_powergate_set(enum tegra_powergate id, bool state) 24*09f455dcSMasahiro Yamada { 25*09f455dcSMasahiro Yamada u32 value, mask = state ? (1 << id) : 0, old_mask; 26*09f455dcSMasahiro Yamada unsigned long start, timeout = 25; 27*09f455dcSMasahiro Yamada 28*09f455dcSMasahiro Yamada value = readl(NV_PA_PMC_BASE + PWRGATE_STATUS); 29*09f455dcSMasahiro Yamada old_mask = value & (1 << id); 30*09f455dcSMasahiro Yamada 31*09f455dcSMasahiro Yamada if (mask == old_mask) 32*09f455dcSMasahiro Yamada return 0; 33*09f455dcSMasahiro Yamada 34*09f455dcSMasahiro Yamada writel(PWRGATE_TOGGLE_START | id, NV_PA_PMC_BASE + PWRGATE_TOGGLE); 35*09f455dcSMasahiro Yamada 36*09f455dcSMasahiro Yamada start = get_timer(0); 37*09f455dcSMasahiro Yamada 38*09f455dcSMasahiro Yamada while (get_timer(start) < timeout) { 39*09f455dcSMasahiro Yamada value = readl(NV_PA_PMC_BASE + PWRGATE_STATUS); 40*09f455dcSMasahiro Yamada if ((value & (1 << id)) == mask) 41*09f455dcSMasahiro Yamada return 0; 42*09f455dcSMasahiro Yamada } 43*09f455dcSMasahiro Yamada 44*09f455dcSMasahiro Yamada return -ETIMEDOUT; 45*09f455dcSMasahiro Yamada } 46*09f455dcSMasahiro Yamada 47*09f455dcSMasahiro Yamada static int tegra_powergate_power_on(enum tegra_powergate id) 48*09f455dcSMasahiro Yamada { 49*09f455dcSMasahiro Yamada return tegra_powergate_set(id, true); 50*09f455dcSMasahiro Yamada } 51*09f455dcSMasahiro Yamada 52*09f455dcSMasahiro Yamada int tegra_powergate_power_off(enum tegra_powergate id) 53*09f455dcSMasahiro Yamada { 54*09f455dcSMasahiro Yamada return tegra_powergate_set(id, false); 55*09f455dcSMasahiro Yamada } 56*09f455dcSMasahiro Yamada 57*09f455dcSMasahiro Yamada static int tegra_powergate_remove_clamping(enum tegra_powergate id) 58*09f455dcSMasahiro Yamada { 59*09f455dcSMasahiro Yamada unsigned long value; 60*09f455dcSMasahiro Yamada 61*09f455dcSMasahiro Yamada /* 62*09f455dcSMasahiro Yamada * The REMOVE_CLAMPING register has the bits for the PCIE and VDEC 63*09f455dcSMasahiro Yamada * partitions reversed. This was originally introduced on Tegra20 but 64*09f455dcSMasahiro Yamada * has since been carried forward for backwards-compatibility. 65*09f455dcSMasahiro Yamada */ 66*09f455dcSMasahiro Yamada if (id == TEGRA_POWERGATE_VDEC) 67*09f455dcSMasahiro Yamada value = 1 << TEGRA_POWERGATE_PCIE; 68*09f455dcSMasahiro Yamada else if (id == TEGRA_POWERGATE_PCIE) 69*09f455dcSMasahiro Yamada value = 1 << TEGRA_POWERGATE_VDEC; 70*09f455dcSMasahiro Yamada else 71*09f455dcSMasahiro Yamada value = 1 << id; 72*09f455dcSMasahiro Yamada 73*09f455dcSMasahiro Yamada writel(value, NV_PA_PMC_BASE + REMOVE_CLAMPING); 74*09f455dcSMasahiro Yamada 75*09f455dcSMasahiro Yamada return 0; 76*09f455dcSMasahiro Yamada } 77*09f455dcSMasahiro Yamada 78*09f455dcSMasahiro Yamada int tegra_powergate_sequence_power_up(enum tegra_powergate id, 79*09f455dcSMasahiro Yamada enum periph_id periph) 80*09f455dcSMasahiro Yamada { 81*09f455dcSMasahiro Yamada int err; 82*09f455dcSMasahiro Yamada 83*09f455dcSMasahiro Yamada reset_set_enable(periph, 1); 84*09f455dcSMasahiro Yamada 85*09f455dcSMasahiro Yamada err = tegra_powergate_power_on(id); 86*09f455dcSMasahiro Yamada if (err < 0) 87*09f455dcSMasahiro Yamada return err; 88*09f455dcSMasahiro Yamada 89*09f455dcSMasahiro Yamada clock_enable(periph); 90*09f455dcSMasahiro Yamada 91*09f455dcSMasahiro Yamada udelay(10); 92*09f455dcSMasahiro Yamada 93*09f455dcSMasahiro Yamada err = tegra_powergate_remove_clamping(id); 94*09f455dcSMasahiro Yamada if (err < 0) 95*09f455dcSMasahiro Yamada return err; 96*09f455dcSMasahiro Yamada 97*09f455dcSMasahiro Yamada udelay(10); 98*09f455dcSMasahiro Yamada 99*09f455dcSMasahiro Yamada reset_set_enable(periph, 0); 100*09f455dcSMasahiro Yamada 101*09f455dcSMasahiro Yamada return 0; 102*09f455dcSMasahiro Yamada } 103