A new user interface for you! Read more...

File rpi2-gop.patch of Package u-boot-rpi2

diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index ac1173d..9d0f32b 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -26,8 +26,12 @@ u64 get_page_table_size(void);
 #define MMU_SECTION_SHIFT	21
 #define MMU_SECTION_SIZE	(1 << MMU_SECTION_SHIFT)
 
+/* These constants need to be synced to the MT_ types in asm/armv8/mmu.h */
 enum dcache_option {
-	DCACHE_OFF = 0x3,
+	DCACHE_OFF = 0 << 2,
+	DCACHE_WRITETHROUGH = 3 << 2,
+	DCACHE_WRITEBACK = 4 << 2,
+	DCACHE_WRITEALLOC = 4 << 2,
 };
 
 #define isb()				\
@@ -172,7 +176,9 @@ void smc_call(struct pt_regs *args);
 #define CR_AFE	(1 << 29)	/* Access flag enable			*/
 #define CR_TE	(1 << 30)	/* Thumb exception enable		*/
 
-#ifndef PGTABLE_SIZE
+#if defined(CONFIG_SYS_ARM_LPAE) && !defined(PGTABLE_SIZE)
+#define PGTABLE_SIZE		(4096 * 5)
+#elif !defined(PGTABLE_SIZE)
 #define PGTABLE_SIZE		(4096 * 4)
 #endif
 
@@ -229,17 +235,50 @@ void save_boot_params_ret(void);
 #define wfi()
 #endif
 
+static inline unsigned long get_cpsr(void)
+{
+	unsigned long cpsr;
+
+	asm volatile("mrs %0, cpsr" : "=r"(cpsr): );
+	return cpsr;
+}
+
+static inline int is_hyp(void)
+{
+#ifdef CONFIG_SYS_ARM_LPAE
+	/* HYP mode requires LPAE ... */
+	return ((get_cpsr() & 0x1f) == 0x1a);
+#else
+	/* ... so without LPAE support we can optimize all hyp code away */
+	return 0;
+#endif
+}
+
 static inline unsigned int get_cr(void)
 {
 	unsigned int val;
-	asm volatile("mrc p15, 0, %0, c1, c0, 0	@ get CR" : "=r" (val) : : "cc");
+
+	if (is_hyp())
+		asm volatile("mrc p15, 4, %0, c1, c0, 0	@ get CR" : "=r" (val)
+								  :
+								  : "cc");
+	else
+		asm volatile("mrc p15, 0, %0, c1, c0, 0	@ get CR" : "=r" (val)
+								  :
+								  : "cc");
 	return val;
 }
 
 static inline void set_cr(unsigned int val)
 {
-	asm volatile("mcr p15, 0, %0, c1, c0, 0	@ set CR"
-	  : : "r" (val) : "cc");
+	if (is_hyp())
+		asm volatile("mcr p15, 4, %0, c1, c0, 0	@ set CR" :
+								  : "r" (val)
+								  : "cc");
+	else
+		asm volatile("mcr p15, 0, %0, c1, c0, 0	@ set CR" :
+								  : "r" (val)
+								  : "cc");
 	isb();
 }
 
@@ -257,12 +296,59 @@ static inline void set_dacr(unsigned int val)
 	isb();
 }
 
-#ifdef CONFIG_CPU_V7
+#ifdef CONFIG_SYS_ARM_LPAE
+/* Long-Descriptor Translation Table Level 1/2 Bits */
+#define TTB_SECT_XN_MASK	(1ULL << 54)
+#define TTB_SECT_NG_MASK	(1 << 11)
+#define TTB_SECT_AF		(1 << 10)
+#define TTB_SECT_SH_MASK	(3 << 8)
+#define TTB_SECT_NS_MASK	(1 << 5)
+#define TTB_SECT_AP		(1 << 6)
+/* Note: TTB AP bits are set elsewhere */
+#define TTB_SECT_MAIR(x)	((x & 0x7) << 2) /* Index into MAIR */
+#define TTB_SECT		(1 << 0)
+#define TTB_PAGETABLE		(3 << 0)
+
+/* TTBCR flags */
+#define TTBCR_EAE		(1 << 31)
+#define TTBCR_T0SZ(x)		((x) << 0)
+#define TTBCR_T1SZ(x)		((x) << 16)
+#define TTBCR_USING_TTBR0	(TTBCR_T0SZ(0) | TTBCR_T1SZ(0))
+#define TTBCR_IRGN0_NC		(0 << 8)
+#define TTBCR_IRGN0_WBWA	(1 << 8)
+#define TTBCR_IRGN0_WT		(2 << 8)
+#define TTBCR_IRGN0_WBNWA	(3 << 8)
+#define TTBCR_IRGN0_MASK	(3 << 8)
+#define TTBCR_ORGN0_NC		(0 << 10)
+#define TTBCR_ORGN0_WBWA	(1 << 10)
+#define TTBCR_ORGN0_WT		(2 << 10)
+#define TTBCR_ORGN0_WBNWA	(3 << 10)
+#define TTBCR_ORGN0_MASK	(3 << 10)
+#define TTBCR_SHARED_NON	(0 << 12)
+#define TTBCR_SHARED_OUTER	(2 << 12)
+#define TTBCR_SHARED_INNER	(3 << 12)
+#define TTBCR_EPD0		(0 << 7)
+
+/*
+ * Memory types
+ */
+#define MEMORY_ATTRIBUTES	((0x00 << (0 * 8)) | (0x88 << (1 * 8)) | \
+				 (0xcc << (2 * 8)) | (0xff << (3 * 8)))
+
+/* options available for data cache on each page */
+enum dcache_option {
+	DCACHE_OFF = TTB_SECT | TTB_SECT_MAIR(0),
+	DCACHE_WRITETHROUGH = TTB_SECT | TTB_SECT_MAIR(1),
+	DCACHE_WRITEBACK = TTB_SECT | TTB_SECT_MAIR(2),
+	DCACHE_WRITEALLOC = TTB_SECT | TTB_SECT_MAIR(3),
+};
+#elif defined(CONFIG_CPU_V7)
 /* Short-Descriptor Translation Table Level 1 Bits */
 #define TTB_SECT_NS_MASK	(1 << 19)
 #define TTB_SECT_NG_MASK	(1 << 17)
 #define TTB_SECT_S_MASK		(1 << 16)
 /* Note: TTB AP bits are set elsewhere */
+#define TTB_SECT_AP		(3 << 10)
 #define TTB_SECT_TEX(x)		((x & 0x7) << 12)
 #define TTB_SECT_DOMAIN(x)	((x & 0xf) << 5)
 #define TTB_SECT_XN_MASK	(1 << 4)
@@ -278,6 +364,7 @@ enum dcache_option {
 	DCACHE_WRITEALLOC = DCACHE_WRITEBACK | TTB_SECT_TEX(1),
 };
 #else
+#define TTB_SECT_AP		(3 << 10)
 /* options available for data cache on each page */
 enum dcache_option {
 	DCACHE_OFF = 0x12,
@@ -289,7 +376,11 @@ enum dcache_option {
 
 /* Size of an MMU section */
 enum {
-	MMU_SECTION_SHIFT	= 20,
+#ifdef CONFIG_SYS_ARM_LPAE
+	MMU_SECTION_SHIFT	= 21, /* 2MB */
+#else
+	MMU_SECTION_SHIFT	= 20, /* 1MB */
+#endif
 	MMU_SECTION_SIZE	= 1 << MMU_SECTION_SHIFT,
 };
 
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 8e18538..849cb89 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -34,11 +34,22 @@ static void cp_delay (void)
 
 void set_section_dcache(int section, enum dcache_option option)
 {
+#ifdef CONFIG_SYS_ARM_LPAE
+	u64 *page_table = (u64 *)gd->arch.tlb_addr;
+	/* Need to set the access flag to not fault */
+	u64 value = TTB_SECT_AP | TTB_SECT_AF;
+#else
 	u32 *page_table = (u32 *)gd->arch.tlb_addr;
-	u32 value;
+	u32 value = TTB_SECT_AP;
+#endif
+
+	/* Add the page offset */
+	value |= ((u32)section << MMU_SECTION_SHIFT);
 
-	value = (section << MMU_SECTION_SHIFT) | (3 << 10);
+	/* Add caching bits */
 	value |= option;
+
+	/* Set PTE */
 	page_table[section] = value;
 }
 
@@ -68,8 +79,9 @@ __weak void dram_bank_mmu_setup(int bank)
 	int	i;
 
 	debug("%s: bank: %d\n", __func__, bank);
-	for (i = bd->bi_dram[bank].start >> 20;
-	     i < (bd->bi_dram[bank].start >> 20) + (bd->bi_dram[bank].size >> 20);
+	for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
+	     i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
+		 (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
 	     i++) {
 #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
 		set_section_dcache(i, DCACHE_WRITETHROUGH);
@@ -89,14 +101,56 @@ static inline void mmu_setup(void)
 
 	arm_init_before_mmu();
 	/* Set up an identity-mapping for all 4GB, rw for everyone */
-	for (i = 0; i < 4096; i++)
+	for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
 		set_section_dcache(i, DCACHE_OFF);
 
 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
 		dram_bank_mmu_setup(i);
 	}
 
-#ifdef CONFIG_CPU_V7
+#ifdef CONFIG_SYS_ARM_LPAE
+	/* Set up 4 PTE entries pointing to our 4 1GB page tables */
+	for (i = 0; i < 4; i++) {
+		u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
+		u64 tpt = gd->arch.tlb_addr + (4096 * i);
+		page_table[i] = tpt | TTB_PAGETABLE;
+	}
+
+	reg = TTBCR_EAE;
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+	reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
+#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
+	reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
+#else
+	reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
+#endif
+
+	if (is_hyp()) {
+		/* Set HCTR to enable LPAE */
+		asm volatile("mcr p15, 4, %0, c2, c0, 2"
+			: : "r" (reg) : "memory");
+		/* Set HTTBR0 */
+		asm volatile("mcrr p15, 4, %0, %1, c2"
+			:
+			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
+			: "memory");
+		/* Set HMAIR */
+		asm volatile("mcr p15, 4, %0, c10, c2, 0"
+			: : "r" (MEMORY_ATTRIBUTES) : "memory");
+	} else {
+		/* Set TTBCR to enable LPAE */
+		asm volatile("mcr p15, 0, %0, c2, c0, 2"
+			: : "r" (reg) : "memory");
+		/* Set 64-bit TTBR0 */
+		asm volatile("mcrr p15, 0, %0, %1, c2"
+			:
+			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
+			: "memory");
+		/* Set MAIR */
+		asm volatile("mcr p15, 0, %0, c10, c2, 0"
+			: : "r" (MEMORY_ATTRIBUTES) : "memory");
+	}
+#elif defined(CONFIG_CPU_V7)
 	/* Set TTBR0 */
 	reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
 #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
diff --git a/arch/arm/mach-bcm283x/init.c b/arch/arm/mach-bcm283x/init.c
index d2d366b..2ec87c2 100644
--- a/arch/arm/mach-bcm283x/init.c
+++ b/arch/arm/mach-bcm283x/init.c
@@ -15,3 +15,10 @@ int arch_cpu_init(void)
 
 	return 0;
 }
+
+#ifdef CONFIG_SYS_ARM_LPAE
+void enable_caches(void)
+{
+	dcache_enable();
+}
+#endif
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index faa6978..3bc4c95 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -141,6 +141,9 @@ static unsigned long do_bootefi_exec(void *efi)
 #ifdef CONFIG_PARTITIONS
 	efi_disk_register();
 #endif
+#ifdef CONFIG_LCD
+	efi_gop_register();
+#endif
 
 	/* Call our payload! */
 #ifdef DEBUG_EFI
diff --git a/common/lcd.c b/common/lcd.c
index 51705ad..783626e 100644
--- a/common/lcd.c
+++ b/common/lcd.c
@@ -66,8 +66,8 @@ void lcd_sync(void)
 	int line_length;
 
 	if (lcd_flush_dcache)
-		flush_dcache_range((u32)lcd_base,
-			(u32)(lcd_base + lcd_get_size(&line_length)));
+		flush_dcache_range((ulong)lcd_base,
+			(ulong)(lcd_base + lcd_get_size(&line_length)));
 #endif
 }
 
Index: u-boot-2016.03/drivers/video/bcm2835.c
===================================================================
--- u-boot-2016.03.orig/drivers/video/bcm2835.c
+++ u-boot-2016.03/drivers/video/bcm2835.c
@@ -107,9 +107,11 @@ void lcd_ctrl_init(void *lcdbase)
 	gd->fb_base = bus_to_phys(
 		msg_setup->allocate_buffer.body.resp.fb_address);
 
-#ifdef CONFIG_ARM64
+	/* Enable dcache for the frame buffer */
+        mmu_set_region_dcache_behaviour(gd->fb_base,
+		ALIGN(msg_setup->allocate_buffer.body.resp.fb_size, PAGE_SIZE),
+		DCACHE_WRITEBACK);
 	lcd_set_flush_dcache(1);
-#endif
 }
 
 void lcd_enable(void)
Index: u-boot-2016.03/include/configs/rpi_2.h
===================================================================
--- u-boot-2016.03.orig/include/configs/rpi_2.h
+++ u-boot-2016.03/include/configs/rpi_2.h
@@ -10,7 +10,7 @@
 #define CONFIG_SKIP_LOWLEVEL_INIT
 #define CONFIG_BCM2836
 #define CONFIG_SYS_CACHELINE_SIZE		64
-#define CONFIG_SYS_DCACHE_OFF
+#define CONFIG_SYS_ARM_LPAE
 
 #include "rpi-common.h"
 
diff --git a/include/efi_api.h b/include/efi_api.h
index 03f6687..6960448 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -365,4 +365,51 @@ struct efi_console_control_protocol
 			uint16_t *password);
 };
 
+#define EFI_GOP_GUID \
+	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
+		 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
+
+#define EFI_GOT_RGBA8		0
+#define EFI_GOT_BGRA8		1
+#define EFI_GOT_BITMASK		2
+
+struct efi_gop_mode_info
+{
+	u32 version;
+	u32 width;
+	u32 height;
+	u32 pixel_format;
+	u32 pixel_bitmask[4];
+	u32 pixels_per_scanline;
+};
+
+struct efi_gop_mode
+{
+	u32 max_mode;
+	u32 mode;
+	struct efi_gop_mode_info *info;
+	unsigned long info_size;
+	efi_physical_addr_t fb_base;
+	unsigned long fb_size;
+};
+
+#define EFI_BLT_VIDEO_FILL		0
+#define EFI_BLT_VIDEO_TO_BLT_BUFFER	1
+#define EFI_BLT_BUFFER_TO_VIDEO		2
+#define EFI_BLT_VIDEO_TO_VIDEO		3
+
+struct efi_gop
+{
+	efi_status_t (EFIAPI *query_mode)(struct efi_gop *this, u32 mode_number,
+					  unsigned long *size_of_info,
+					  struct efi_gop_mode_info **info);
+	efi_status_t (EFIAPI *set_mode)(struct efi_gop *this, u32 mode_number);
+	efi_status_t (EFIAPI *blt)(struct efi_gop *this, void *buffer,
+				   unsigned long operation, unsigned long sx,
+				   unsigned long sy, unsigned long dx,
+				   unsigned long dy, unsigned long width,
+				   unsigned long height, unsigned long delta);
+	struct efi_gop_mode *mode;
+};
+
 #endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 385239b..129f2b7 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -88,6 +88,8 @@ extern struct list_head efi_obj_list;
 
 /* Called by bootefi to make all disk storage accessible as EFI objects */
 int efi_disk_register(void);
+/* Called by bootefi to make GOP (graphical) interface available */
+int efi_gop_register(void);
 /*
  * Stub implementation for a protocol opener that just returns the handle as
  * interface
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 28725a2..83e31f6 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -9,4 +9,5 @@
 
 obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
 obj-y += efi_memory.o
+obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_PARTITIONS) += efi_disk.o
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c
new file mode 100644
index 0000000..bdd62bc
--- /dev/null
+++ b/lib/efi_loader/efi_gop.c
@@ -0,0 +1,152 @@
+/*
+ *  EFI application disk support
+ *
+ *  Copyright (c) 2016 Alexander Graf
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <inttypes.h>
+#include <lcd.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const efi_guid_t efi_gop_guid = EFI_GOP_GUID;
+
+struct efi_gop_obj {
+	/* Generic EFI object parent class data */
+	struct efi_object parent;
+	/* EFI Interface callback struct for gop */
+	struct efi_gop ops;
+	/* The only mode we support */
+	struct efi_gop_mode_info info;
+	struct efi_gop_mode mode;
+};
+
+static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number,
+					  unsigned long *size_of_info,
+					  struct efi_gop_mode_info **info)
+{
+	struct efi_gop_obj *gopobj;
+
+	EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info);
+
+	gopobj = container_of(this, struct efi_gop_obj, ops);
+	*size_of_info = sizeof(gopobj->info);
+	*info = &gopobj->info;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
+{
+	EFI_ENTRY("%p, %x", this, mode_number);
+
+	if (mode_number != 0)
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer,
+				   unsigned long operation, unsigned long sx,
+				   unsigned long sy, unsigned long dx,
+				   unsigned long dy, unsigned long width,
+				   unsigned long height, unsigned long delta)
+{
+	int i, j, line_len16, line_len32;
+	void *fb;
+
+	EFI_ENTRY("%p, %p, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx", this,
+		  buffer, operation, sx, sy, dx, dy, width, height, delta);
+
+	if (operation != EFI_BLT_BUFFER_TO_VIDEO)
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	fb = (void*)gd->fb_base;
+	line_len16 = panel_info.vl_col * sizeof(u16);
+	line_len32 = panel_info.vl_col * sizeof(u32);
+
+	/* Copy the contents line by line */
+
+	switch (panel_info.vl_bpix) {
+	case LCD_COLOR32:
+		for (i = 0; i < height; i++) {
+			u32 *dest = fb + ((i + dy)  * line_len32) +
+					 (dx * sizeof(u32));
+			u32 *src = buffer + ((i + sy)  * line_len32) +
+					 (sx * sizeof(u32));
+
+			/* Same color format, just memcpy */
+			memcpy(dest, src, width * sizeof(u32));
+		}
+		break;
+	case LCD_COLOR16:
+		for (i = 0; i < height; i++) {
+			u16 *dest = fb + ((i + dy)  * line_len16) +
+					 (dx * sizeof(u16));
+			u32 *src = buffer + ((i + sy)  * line_len32) +
+					 (sx * sizeof(u32));
+
+			/* Convert from rgb888 to rgb565 */
+			for (j = 0; j < width; j++) {
+				u32 rgb888 = src[j];
+				dest[j] = ((((rgb888 >> (16 + 3)) & 0x1f) << 11) |
+					   (((rgb888 >> (8 + 2)) & 0x3f) << 5) |
+					   (((rgb888 >> (0 + 3)) & 0x1f) << 0));
+			}
+		}
+		break;
+	}
+
+	lcd_sync();
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+/* This gets called from do_bootefi_exec(). */
+int efi_gop_register(void)
+{
+	struct efi_gop_obj *gopobj;
+	int line_len;
+
+	switch (panel_info.vl_bpix) {
+	case LCD_COLOR32:
+	case LCD_COLOR16:
+		break;
+	default:
+		/* So far, we only work in 16 or 32 bit mode */
+		return -1;
+	}
+
+	gopobj = calloc(1, sizeof(*gopobj));
+
+	/* Fill in object data */
+	gopobj->parent.protocols[0].guid = &efi_gop_guid;
+	gopobj->parent.protocols[0].open = efi_return_handle;
+	gopobj->parent.handle = &gopobj->ops;
+	gopobj->ops.query_mode = gop_query_mode;
+	gopobj->ops.set_mode = gop_set_mode;
+	gopobj->ops.blt = gop_blt;
+	gopobj->ops.mode = &gopobj->mode;
+
+	gopobj->mode.max_mode = 1;
+	gopobj->mode.info = &gopobj->info;
+	gopobj->mode.info_size = sizeof(gopobj->info);
+	gopobj->mode.fb_base = gd->fb_base;
+	gopobj->mode.fb_size = lcd_get_size(&line_len);
+
+	gopobj->info.version = 0;
+	gopobj->info.width = panel_info.vl_col;
+	gopobj->info.height = panel_info.vl_row;
+	gopobj->info.pixel_format = EFI_GOT_RGBA8;
+	gopobj->info.pixels_per_scanline = panel_info.vl_col;
+
+	/* Hook up to the device list */
+	list_add_tail(&gopobj->parent.link, &efi_obj_list);
+
+	return 0;
+}