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