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