ARM: tegra: clock: Add SoC-to-DDR bit swap support
Alex Frid [Sat, 18 Feb 2012 07:25:06 +0000 (23:25 -0800)]
Since Tegra3 allows bit swapping when routing SoC-to-DDR data bus,
added the respective decoding mechanism for reading LPDDR2 mode
registers. Populated mapping table for PM269 board.

Bug 939626

Signed-off-by: Alex Frid <afrid@nvidia.com>
(cherry picked from commit 5f5329596167681b528c87fd088d60030eee6fdc)

Change-Id: I6670110a828df4264b8f7a8c8e6e67611a830033
Reviewed-on: http://git-master/r/89350
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

arch/arm/mach-tegra/board-cardhu-memory.c
arch/arm/mach-tegra/tegra3_emc.c
arch/arm/mach-tegra/tegra3_emc.h

index a2492b1..019014c 100644 (file)
@@ -4828,6 +4828,45 @@ static const struct tegra_emc_table cardhu_emc_tables_edb8132b2ma[] = {
        },
 };
 
+static const u32 pm269_bit_swap_map[32] = {
+      /* DDR bit #    SoC bit # */
+       [0]  = 0x1 << 1,
+       [1]  = 0x1 << 2,
+       [2]  = 0x1 << 3,
+       [3]  = 0x1 << 0,
+       [4]  = 0x1 << 7,
+       [5]  = 0x1 << 5,
+       [6]  = 0x1 << 6,
+       [7]  = 0x1 << 4,
+
+       [8]  = 0x1 << 13,
+       [9]  = 0x1 << 9,
+       [10] = 0x1 << 8,
+       [11] = 0x1 << 12,
+       [12] = 0x1 << 11,
+       [13] = 0x1 << 10,
+       [14] = 0x1 << 14,
+       [15] = 0x1 << 15,
+
+       [16] = 0x1 << 20,
+       [17] = 0x1 << 23,
+       [18] = 0x1 << 16,
+       [19] = 0x1 << 19,
+       [20] = 0x1 << 18,
+       [21] = 0x1 << 21,
+       [22] = 0x1 << 22,
+       [23] = 0x1 << 17,
+
+       [24] = 0x1 << 27,
+       [25] = 0x1 << 30,
+       [26] = 0x1 << 31,
+       [27] = 0x1 << 28,
+       [28] = 0x1 << 26,
+       [29] = 0x1 << 25,
+       [30] = 0x1 << 24,
+       [31] = 0x1 << 29,
+};
+
 int cardhu_emc_init(void)
 {
        struct board_info board;
@@ -4836,6 +4875,9 @@ int cardhu_emc_init(void)
 
        switch (board.board_id) {
        case BOARD_PM269:
+               tegra_init_dram_bit_map(pm269_bit_swap_map,
+                               ARRAY_SIZE(pm269_bit_swap_map));
+               /* fall through */
        case BOARD_E1257:
                if (MEMORY_TYPE(board.sku) == SKU_MEMORY_ELPIDA)
                        tegra_init_emc(cardhu_emc_tables_edb8132b2ma,
index 746caea..0ceed66 100644 (file)
@@ -192,6 +192,7 @@ static struct tegra_emc_table start_timing;
 static const struct tegra_emc_table *emc_timing;
 static unsigned long dram_over_temp_state = DRAM_OVER_TEMP_NONE;
 
+static const u32 *dram_to_soc_bit_map;
 static const struct tegra_emc_table *tegra_emc_table;
 static int tegra_emc_table_size;
 
@@ -1051,6 +1052,12 @@ void tegra_emc_timing_invalidate(void)
        emc_timing = NULL;
 }
 
+void tegra_init_dram_bit_map(const u32 *bit_map, int map_size)
+{
+       BUG_ON(map_size != 32);
+       dram_to_soc_bit_map = bit_map;
+}
+
 void tegra_emc_dram_type_init(struct clk *c)
 {
        emc = c;
@@ -1069,6 +1076,29 @@ int tegra_emc_get_dram_type(void)
        return dram_type;
 }
 
+static u32 soc_to_dram_bit_swap(u32 soc_val, u32 dram_mask, u32 dram_shift)
+{
+       int bit;
+       u32 dram_val = 0;
+
+       /* tegra clocks definitions use shifted mask always */
+       if (!dram_to_soc_bit_map)
+               return soc_val & dram_mask;
+
+       for (bit = dram_shift; bit < 32; bit++) {
+               u32 dram_bit_mask = 0x1 << bit;
+               u32 soc_bit_mask = dram_to_soc_bit_map[bit];
+
+               if (!(dram_bit_mask & dram_mask))
+                       break;
+
+               if (soc_bit_mask & soc_val)
+                       dram_val |= dram_bit_mask;
+       }
+
+       return dram_val;
+}
+
 static int emc_read_mrr(int dev, int addr)
 {
        int ret;
@@ -1089,7 +1119,6 @@ static int emc_read_mrr(int dev, int addr)
        if (ret)
                return ret;
 
-       /* FIXME: bit swap decoding */
        val = emc_readl(EMC_MRR) & EMC_MRR_DATA_MASK;
        return val;
 }
@@ -1106,9 +1135,10 @@ int tegra_emc_get_dram_temperature(void)
                spin_unlock_irqrestore(&emc_access_lock, flags);
                return mr4;
        }
-
-       mr4 &= LPDDR2_MR4_TEMP_MASK;
        spin_unlock_irqrestore(&emc_access_lock, flags);
+
+       mr4 = soc_to_dram_bit_swap(
+               mr4, LPDDR2_MR4_TEMP_MASK, LPDDR2_MR4_TEMP_SHIFT);
        return mr4;
 }
 
index 48b2d9c..cfde92c 100644 (file)
@@ -54,6 +54,7 @@ struct clk;
 
 void tegra_init_emc(const struct tegra_emc_table *table, int table_size);
 
+void tegra_init_dram_bit_map(const u32 *bit_map, int map_size);
 void tegra_emc_dram_type_init(struct clk *c);
 int tegra_emc_get_dram_type(void);
 int tegra_emc_get_dram_temperature(void);
@@ -158,7 +159,8 @@ enum {
 #define EMC_MRR_MA_SHIFT                       16
 #define EMC_MRR_MA_MASK                                (0xFF << EMC_MRR_MA_SHIFT)
 #define EMC_MRR_DATA_MASK                      ((0x1 << EMC_MRR_MA_SHIFT) - 1)
-#define LPDDR2_MR4_TEMP_MASK                   0x7
+#define LPDDR2_MR4_TEMP_SHIFT                  0
+#define LPDDR2_MR4_TEMP_MASK                   (0x7 << LPDDR2_MR4_TEMP_SHIFT)
 
 #define EMC_XM2DQSPADCTRL3                     0xf8
 #define EMC_XM2DQSPADCTRL3_VREF_ENABLE         (0x1 << 5)