static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot)
 {
-       set_pud(pud, __pud(pmd | prot));
+       set_pud(pud, __pud(__phys_to_pud_val(pmd) | prot));
 }
 
 static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 
 static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot)
 {
-       set_pgd(pgdp, __pgd(pud | prot));
+       set_pgd(pgdp, __pgd(__phys_to_pgd_val(pud) | prot));
 }
 
 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
 static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
                                  pmdval_t prot)
 {
-       set_pmd(pmdp, __pmd(pte | prot));
+       set_pmd(pmdp, __pmd(__phys_to_pmd_val(pte) | prot));
 }
 
 /*
 
 
 #define pte_ERROR(pte)         __pte_error(__FILE__, __LINE__, pte_val(pte))
 
-#define pte_pfn(pte)           ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT)
+/*
+ * Macros to convert between a physical address and its placement in a
+ * page table entry, taking care of 52-bit addresses.
+ */
+#ifdef CONFIG_ARM64_PA_BITS_52
+#define __pte_to_phys(pte)     \
+       ((pte_val(pte) & PTE_ADDR_LOW) | ((pte_val(pte) & PTE_ADDR_HIGH) << 36))
+#define __phys_to_pte_val(phys)        (((phys) | ((phys) >> 36)) & PTE_ADDR_MASK)
+#else
+#define __pte_to_phys(pte)     (pte_val(pte) & PTE_ADDR_MASK)
+#define __phys_to_pte_val(phys)        (phys)
+#endif
 
-#define pfn_pte(pfn,prot)      (__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+#define pte_pfn(pte)           (__pte_to_phys(pte) >> PAGE_SHIFT)
+#define pfn_pte(pfn,prot)      \
+       __pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
 #define pte_none(pte)          (!pte_val(pte))
 #define pte_clear(mm,addr,ptep)        set_pte(ptep, __pte(0))
 
 #define __HAVE_ARCH_PTE_SPECIAL
 
+static inline pte_t pgd_pte(pgd_t pgd)
+{
+       return __pte(pgd_val(pgd));
+}
+
 static inline pte_t pud_pte(pud_t pud)
 {
        return __pte(pud_val(pud));
 
 #define pmd_mkhuge(pmd)                (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
 
-#define pmd_pfn(pmd)           (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
-#define pfn_pmd(pfn,prot)      (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+#define __pmd_to_phys(pmd)     __pte_to_phys(pmd_pte(pmd))
+#define __phys_to_pmd_val(phys)        __phys_to_pte_val(phys)
+#define pmd_pfn(pmd)           ((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT)
+#define pfn_pmd(pfn,prot)      __pmd(__phys_to_pmd_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
 #define mk_pmd(page,prot)      pfn_pmd(page_to_pfn(page),prot)
 
 #define pud_write(pud)         pte_write(pud_pte(pud))
-#define pud_pfn(pud)           (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
-#define pfn_pud(pfn,prot)      (__pud(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+
+#define __pud_to_phys(pud)     __pte_to_phys(pud_pte(pud))
+#define __phys_to_pud_val(phys)        __phys_to_pte_val(phys)
+#define pud_pfn(pud)           ((__pud_to_phys(pud) & PUD_MASK) >> PAGE_SHIFT)
+#define pfn_pud(pfn,prot)      __pud(__phys_to_pud_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
 #define set_pmd_at(mm, addr, pmdp, pmd)        set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd))
 
+#define __pgd_to_phys(pgd)     __pte_to_phys(pgd_pte(pgd))
+#define __phys_to_pgd_val(phys)        __phys_to_pte_val(phys)
+
 #define __pgprot_modify(prot,mask,bits) \
        __pgprot((pgprot_val(prot) & ~(mask)) | (bits))
 
 
 static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
 {
-       return pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK;
+       return __pmd_to_phys(pmd);
 }
 
 /* Find an entry in the third-level page table. */
 #define pte_set_fixmap_offset(pmd, addr)       pte_set_fixmap(pte_offset_phys(pmd, addr))
 #define pte_clear_fixmap()             clear_fixmap(FIX_PTE)
 
-#define pmd_page(pmd)          pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
+#define pmd_page(pmd)          pfn_to_page(__phys_to_pfn(__pmd_to_phys(pmd)))
 
 /* use ONLY for statically allocated translation tables */
 #define pte_offset_kimg(dir,addr)      ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
 
 static inline phys_addr_t pud_page_paddr(pud_t pud)
 {
-       return pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK;
+       return __pud_to_phys(pud);
 }
 
 /* Find an entry in the second-level page table. */
 #define pmd_set_fixmap_offset(pud, addr)       pmd_set_fixmap(pmd_offset_phys(pud, addr))
 #define pmd_clear_fixmap()             clear_fixmap(FIX_PMD)
 
-#define pud_page(pud)          pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
+#define pud_page(pud)          pfn_to_page(__phys_to_pfn(__pud_to_phys(pud)))
 
 /* use ONLY for statically allocated translation tables */
 #define pmd_offset_kimg(dir,addr)      ((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
 
 static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
 {
-       return pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK;
+       return __pgd_to_phys(pgd);
 }
 
 /* Find an entry in the frst-level page table. */
 #define pud_set_fixmap_offset(pgd, addr)       pud_set_fixmap(pud_offset_phys(pgd, addr))
 #define pud_clear_fixmap()             clear_fixmap(FIX_PUD)
 
-#define pgd_page(pgd)          pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK))
+#define pgd_page(pgd)          pfn_to_page(__phys_to_pfn(__pgd_to_phys(pgd)))
 
 /* use ONLY for statically allocated translation tables */
 #define pud_offset_kimg(dir,addr)      ((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))