linux/arch/arm/mach-tegra/tegra2_emc.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011 Google, Inc.
   3 *
   4 * Author:
   5 *      Colin Cross <ccross@android.com>
   6 *
   7 * This software is licensed under the terms of the GNU General Public
   8 * License version 2, as published by the Free Software Foundation, and
   9 * may be copied, distributed, and modified under those terms.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 */
  17
  18#include <linux/kernel.h>
  19#include <linux/clk.h>
  20#include <linux/err.h>
  21#include <linux/io.h>
  22#include <linux/module.h>
  23
  24#include <mach/iomap.h>
  25
  26#include "tegra2_emc.h"
  27
  28#ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
  29static bool emc_enable = true;
  30#else
  31static bool emc_enable;
  32#endif
  33module_param(emc_enable, bool, 0644);
  34
  35static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE);
  36static const struct tegra_emc_table *tegra_emc_table;
  37static int tegra_emc_table_size;
  38
  39static inline void emc_writel(u32 val, unsigned long addr)
  40{
  41        writel(val, emc + addr);
  42}
  43
  44static inline u32 emc_readl(unsigned long addr)
  45{
  46        return readl(emc + addr);
  47}
  48
  49static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
  50        0x2c,   /* RC */
  51        0x30,   /* RFC */
  52        0x34,   /* RAS */
  53        0x38,   /* RP */
  54        0x3c,   /* R2W */
  55        0x40,   /* W2R */
  56        0x44,   /* R2P */
  57        0x48,   /* W2P */
  58        0x4c,   /* RD_RCD */
  59        0x50,   /* WR_RCD */
  60        0x54,   /* RRD */
  61        0x58,   /* REXT */
  62        0x5c,   /* WDV */
  63        0x60,   /* QUSE */
  64        0x64,   /* QRST */
  65        0x68,   /* QSAFE */
  66        0x6c,   /* RDV */
  67        0x70,   /* REFRESH */
  68        0x74,   /* BURST_REFRESH_NUM */
  69        0x78,   /* PDEX2WR */
  70        0x7c,   /* PDEX2RD */
  71        0x80,   /* PCHG2PDEN */
  72        0x84,   /* ACT2PDEN */
  73        0x88,   /* AR2PDEN */
  74        0x8c,   /* RW2PDEN */
  75        0x90,   /* TXSR */
  76        0x94,   /* TCKE */
  77        0x98,   /* TFAW */
  78        0x9c,   /* TRPAB */
  79        0xa0,   /* TCLKSTABLE */
  80        0xa4,   /* TCLKSTOP */
  81        0xa8,   /* TREFBW */
  82        0xac,   /* QUSE_EXTRA */
  83        0x114,  /* FBIO_CFG6 */
  84        0xb0,   /* ODT_WRITE */
  85        0xb4,   /* ODT_READ */
  86        0x104,  /* FBIO_CFG5 */
  87        0x2bc,  /* CFG_DIG_DLL */
  88        0x2c0,  /* DLL_XFORM_DQS */
  89        0x2c4,  /* DLL_XFORM_QUSE */
  90        0x2e0,  /* ZCAL_REF_CNT */
  91        0x2e4,  /* ZCAL_WAIT_CNT */
  92        0x2a8,  /* AUTO_CAL_INTERVAL */
  93        0x2d0,  /* CFG_CLKTRIM_0 */
  94        0x2d4,  /* CFG_CLKTRIM_1 */
  95        0x2d8,  /* CFG_CLKTRIM_2 */
  96};
  97
  98/* Select the closest EMC rate that is higher than the requested rate */
  99long tegra_emc_round_rate(unsigned long rate)
 100{
 101        int i;
 102        int best = -1;
 103        unsigned long distance = ULONG_MAX;
 104
 105        if (!tegra_emc_table)
 106                return -EINVAL;
 107
 108        if (!emc_enable)
 109                return -EINVAL;
 110
 111        pr_debug("%s: %lu\n", __func__, rate);
 112
 113        /*
 114         * The EMC clock rate is twice the bus rate, and the bus rate is
 115         * measured in kHz
 116         */
 117        rate = rate / 2 / 1000;
 118
 119        for (i = 0; i < tegra_emc_table_size; i++) {
 120                if (tegra_emc_table[i].rate >= rate &&
 121                    (tegra_emc_table[i].rate - rate) < distance) {
 122                        distance = tegra_emc_table[i].rate - rate;
 123                        best = i;
 124                }
 125        }
 126
 127        if (best < 0)
 128                return -EINVAL;
 129
 130        pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate);
 131
 132        return tegra_emc_table[best].rate * 2 * 1000;
 133}
 134
 135/*
 136 * The EMC registers have shadow registers.  When the EMC clock is updated
 137 * in the clock controller, the shadow registers are copied to the active
 138 * registers, allowing glitchless memory bus frequency changes.
 139 * This function updates the shadow registers for a new clock frequency,
 140 * and relies on the clock lock on the emc clock to avoid races between
 141 * multiple frequency changes
 142 */
 143int tegra_emc_set_rate(unsigned long rate)
 144{
 145        int i;
 146        int j;
 147
 148        if (!tegra_emc_table)
 149                return -EINVAL;
 150
 151        /*
 152         * The EMC clock rate is twice the bus rate, and the bus rate is
 153         * measured in kHz
 154         */
 155        rate = rate / 2 / 1000;
 156
 157        for (i = 0; i < tegra_emc_table_size; i++)
 158                if (tegra_emc_table[i].rate == rate)
 159                        break;
 160
 161        if (i >= tegra_emc_table_size)
 162                return -EINVAL;
 163
 164        pr_debug("%s: setting to %lu\n", __func__, rate);
 165
 166        for (j = 0; j < TEGRA_EMC_NUM_REGS; j++)
 167                emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]);
 168
 169        emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]);
 170
 171        return 0;
 172}
 173
 174void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
 175{
 176        tegra_emc_table = table;
 177        tegra_emc_table_size = table_size;
 178}
 179