Merge pull request #161 from danh-arm/lm/calc-tcr-bits

Calculate TCR bits based on VA and PA
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 5dc488b..ff91efc 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -211,8 +211,23 @@
  * TCR defintions
  */
 #define TCR_EL3_RES1		((1UL << 31) | (1UL << 23))
+#define TCR_EL1_IPS_SHIFT	32
+#define TCR_EL3_PS_SHIFT	16
+
+/* (internal) physical address size bits in EL3/EL1 */
+#define TCR_PS_BITS_4GB		(0x0)
+#define TCR_PS_BITS_64GB	(0x1)
+#define TCR_PS_BITS_1TB		(0x2)
+#define TCR_PS_BITS_4TB		(0x3)
+#define TCR_PS_BITS_16TB	(0x4)
+#define TCR_PS_BITS_256TB	(0x5)
 
-#define TCR_T0SZ_4GB		32
+#define ADDR_MASK_48_TO_63	0xFFFF000000000000UL
+#define ADDR_MASK_44_TO_47	0x0000F00000000000UL
+#define ADDR_MASK_42_TO_43	0x00000C0000000000UL
+#define ADDR_MASK_40_TO_41	0x0000030000000000UL
+#define ADDR_MASK_36_TO_39	0x000000F000000000UL
+#define ADDR_MASK_32_TO_35	0x0000000F00000000UL
 
 #define TCR_RGN_INNER_NC	(0x0 << 8)
 #define TCR_RGN_INNER_WBA	(0x1 << 8)
diff --git a/lib/aarch64/xlat_tables.c b/lib/aarch64/xlat_tables.c
index 1b99cc8..f1d658d 100644
--- a/lib/aarch64/xlat_tables.c
+++ b/lib/aarch64/xlat_tables.c
@@ -31,6 +31,7 @@
 #include <arch.h>
 #include <arch_helpers.h>
 #include <assert.h>
+#include <cassert.h>
 #include <platform_def.h>
 #include <string.h>
 #include <xlat_tables.h>
@@ -46,6 +47,7 @@
 #define debug_print(...) ((void)0)
 #endif
 
+CASSERT(ADDR_SPACE_SIZE > 0, assert_valid_addr_space_size);
 
 #define UNSET_DESC	~0ul
 
@@ -58,6 +60,9 @@
 __aligned(XLAT_TABLE_SIZE) __attribute__((section("xlat_table")));
 
 static unsigned next_xlat;
+static unsigned long max_pa;
+static unsigned long max_va;
+static unsigned long tcr_ps_bits;
 
 /*
  * Array of all memory regions stored in order of ascending base address.
@@ -85,6 +90,8 @@
 {
 	mmap_region_t *mm = mmap;
 	mmap_region_t *mm_last = mm + sizeof(mmap) / sizeof(mmap[0]) - 1;
+	unsigned long pa_end = base_pa + size - 1;
+	unsigned long va_end = base_va + size - 1;
 
 	assert(IS_PAGE_ALIGNED(base_pa));
 	assert(IS_PAGE_ALIGNED(base_va));
@@ -107,6 +114,11 @@
 	mm->base_va = base_va;
 	mm->size = size;
 	mm->attr = attr;
+
+	if (pa_end > max_pa)
+		max_pa = pa_end;
+	if (va_end > max_va)
+		max_va = va_end;
 }
 
 void mmap_add(const mmap_region_t *mm)
@@ -233,10 +245,40 @@
 	return mm;
 }
 
+static unsigned int calc_physical_addr_size_bits(unsigned long max_addr)
+{
+	/* Physical address can't exceed 48 bits */
+	assert((max_addr & ADDR_MASK_48_TO_63) == 0);
+
+	/* 48 bits address */
+	if (max_addr & ADDR_MASK_44_TO_47)
+		return TCR_PS_BITS_256TB;
+
+	/* 44 bits address */
+	if (max_addr & ADDR_MASK_42_TO_43)
+		return TCR_PS_BITS_16TB;
+
+	/* 42 bits address */
+	if (max_addr & ADDR_MASK_40_TO_41)
+		return TCR_PS_BITS_4TB;
+
+	/* 40 bits address */
+	if (max_addr & ADDR_MASK_36_TO_39)
+		return TCR_PS_BITS_1TB;
+
+	/* 36 bits address */
+	if (max_addr & ADDR_MASK_32_TO_35)
+		return TCR_PS_BITS_64GB;
+
+	return TCR_PS_BITS_4GB;
+}
+
 void init_xlat_tables(void)
 {
 	print_mmap();
 	init_xlation_table(mmap, 0, l1_xlation_table, 1);
+	tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
+	assert(max_va < ADDR_SPACE_SIZE);
 }
 
 /*******************************************************************************
@@ -270,7 +312,8 @@
 		/* Set TCR bits as well. */				\
 		/* Inner & outer WBWA & shareable + T0SZ = 32 */	\
 		tcr = TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA |	\
-			TCR_RGN_INNER_WBA | TCR_T0SZ_4GB;		\
+			TCR_RGN_INNER_WBA |				\
+			(64 - __builtin_ctzl(ADDR_SPACE_SIZE));		\
 		tcr |= _tcr_extra;					\
 		write_tcr_el##_el(tcr);					\
 									\
@@ -295,5 +338,9 @@
 	}
 
 /* Define EL1 and EL3 variants of the function enabling the MMU */
-DEFINE_ENABLE_MMU_EL(1, 0, tlbivmalle1)
-DEFINE_ENABLE_MMU_EL(3, TCR_EL3_RES1, tlbialle3)
+DEFINE_ENABLE_MMU_EL(1,
+		(tcr_ps_bits << TCR_EL1_IPS_SHIFT),
+		tlbivmalle1)
+DEFINE_ENABLE_MMU_EL(3,
+		TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT),
+		tlbialle3)