bios_emulator: Add some VESA interface debugging

Allow the supported modes to be listed when in debug mode.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c
index 93b815c..7ea5fa6 100644
--- a/drivers/bios_emulator/atibios.c
+++ b/drivers/bios_emulator/atibios.c
@@ -62,40 +62,158 @@
 static u32 saveBaseAddress18;
 static u32 saveBaseAddress20;
 
-static void atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
-				  struct vbe_mode_info *mode_info)
+/* Addres im memory of VBE region */
+const int vbe_offset = 0x2000;
+
+static const void *bios_ptr(const void *buf, BE_VGAInfo *vga_info,
+			    u32 x86_dword_ptr)
 {
+	u32 seg_ofs, flat;
+
+	seg_ofs = le32_to_cpu(x86_dword_ptr);
+	flat = ((seg_ofs & 0xffff0000) >> 12) | (seg_ofs & 0xffff);
+	if (flat >= 0xc0000)
+		return vga_info->BIOSImage + flat - 0xc0000;
+	else
+		return buf + (flat - vbe_offset);
+}
+
+static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
+			      int vesa_mode, struct vbe_mode_info *mode_info)
+{
+	void *buffer = (void *)(M.mem_base + vbe_offset);
+	u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
+	u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
+	struct vesa_mode_info *vm;
+	struct vbe_info *info;
+	const u16 *modes_bios, *ptr;
+	u16 *modes;
+	int size;
+
+	debug("VBE: Getting information\n");
+	regs->e.eax = VESA_GET_INFO;
+	regs->e.esi = buffer_seg;
+	regs->e.edi = buffer_adr;
+	info = buffer;
+	memset(info, '\0', sizeof(*info));
+	strcpy(info->signature, "VBE2");
+	BE_int86(0x10, regs, regs);
+	if (regs->e.eax != 0x4f) {
+		debug("VESA_GET_INFO: error %x\n", regs->e.eax);
+		return -ENOSYS;
+	}
+	debug("version %x\n", le16_to_cpu(info->version));
+	debug("oem '%s'\n", (char *)bios_ptr(buffer, vga_info,
+					     info->oem_string_ptr));
+	debug("vendor '%s'\n", (char *)bios_ptr(buffer, vga_info,
+						info->vendor_name_ptr));
+	debug("product '%s'\n", (char *)bios_ptr(buffer, vga_info,
+						 info->product_name_ptr));
+	debug("rev '%s'\n", (char *)bios_ptr(buffer, vga_info,
+					     info->product_rev_ptr));
+	modes_bios = bios_ptr(buffer, vga_info, info->modes_ptr);
+	debug("Modes: ");
+	for (ptr = modes_bios; *ptr != 0xffff; ptr++)
+		debug("%x ", le16_to_cpu(*ptr));
+	debug("\nmemory %dMB\n", le16_to_cpu(info->total_memory) >> 4);
+	size = (ptr - modes_bios) * sizeof(u16) + 2;
+	modes = malloc(size);
+	if (!modes)
+		return -ENOMEM;
+	memcpy(modes, modes_bios, size);
+
+	regs->e.eax = VESA_GET_CUR_MODE;
+	BE_int86(0x10, regs, regs);
+	if (regs->e.eax != 0x4f) {
+		debug("VESA_GET_CUR_MODE: error %x\n", regs->e.eax);
+		return -ENOSYS;
+	}
+	debug("Current mode %x\n", regs->e.ebx);
+
+	for (ptr = modes; *ptr != 0xffff; ptr++) {
+		int mode = le16_to_cpu(*ptr);
+		bool linear_ok;
+		int attr;
+
+		break;
+		debug("Mode %x: ", mode);
+		memset(buffer, '\0', sizeof(struct vbe_mode_info));
+		regs->e.eax = VESA_GET_MODE_INFO;
+		regs->e.ebx = 0;
+		regs->e.ecx = mode;
+		regs->e.edx = 0;
+		regs->e.esi = buffer_seg;
+		regs->e.edi = buffer_adr;
+		BE_int86(0x10, regs, regs);
+		if (regs->e.eax != 0x4f) {
+			debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
+			continue;
+		}
+		memcpy(mode_info->mode_info_block, buffer,
+		       sizeof(struct vesa_mode_info));
+		mode_info->valid = true;
+		vm = &mode_info->vesa;
+		attr = le16_to_cpu(vm->mode_attributes);
+		linear_ok = attr & 0x80;
+		debug("res %d x %d, %d bpp, mm %d, (Linear %s, attr %02x)\n",
+		      le16_to_cpu(vm->x_resolution),
+		      le16_to_cpu(vm->y_resolution),
+		      vm->bits_per_pixel, vm->memory_model,
+		      linear_ok ? "OK" : "not available",
+		      attr);
+		debug("\tRGB pos=%d,%d,%d, size=%d,%d,%d\n",
+		      vm->red_mask_pos, vm->green_mask_pos, vm->blue_mask_pos,
+		      vm->red_mask_size, vm->green_mask_size,
+		      vm->blue_mask_size);
+	}
+
+	return 0;
+}
+
+static int atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
+				 struct vbe_mode_info *mode_info)
+{
+	void *buffer = (void *)(M.mem_base + vbe_offset);
+	u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
+	u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
+	struct vesa_mode_info *vm;
+
 	debug("VBE: Setting VESA mode %#04x\n", vesa_mode);
-	/* request linear framebuffer mode */
-	vesa_mode |= (1 << 14);
-	/* request clearing of framebuffer */
-	vesa_mode &= ~(1 << 15);
 	regs->e.eax = VESA_SET_MODE;
 	regs->e.ebx = vesa_mode;
+	/* request linear framebuffer mode and don't clear display */
+	regs->e.ebx |= (1 << 14) | (1 << 15);
 	BE_int86(0x10, regs, regs);
+	if (regs->e.eax != 0x4f) {
+		debug("VESA_SET_MODE: error %x\n", regs->e.eax);
+		return -ENOSYS;
+	}
 
-	int offset = 0x2000;
-	void *buffer = (void *)(M.mem_base + offset);
-
-	u16 buffer_seg = (((unsigned long)offset) >> 4) & 0xff00;
-	u16 buffer_adr = ((unsigned long)offset) & 0xffff;
+	memset(buffer, '\0', sizeof(struct vbe_mode_info));
+	debug("VBE: Geting info for VESA mode %#04x\n", vesa_mode);
 	regs->e.eax = VESA_GET_MODE_INFO;
-	regs->e.ebx = 0;
 	regs->e.ecx = vesa_mode;
-	regs->e.edx = 0;
 	regs->e.esi = buffer_seg;
 	regs->e.edi = buffer_adr;
 	BE_int86(0x10, regs, regs);
-	memcpy(mode_info->mode_info_block, buffer,
-	       sizeof(struct vbe_mode_info));
-	mode_info->valid = true;
+	if (regs->e.eax != 0x4f) {
+		debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
+		return -ENOSYS;
+	}
 
-	vesa_mode |= (1 << 14);
-	/* request clearing of framebuffer */
-	vesa_mode &= ~(1 << 15);
-	regs->e.eax = VESA_SET_MODE;
-	regs->e.ebx = vesa_mode;
-	BE_int86(0x10, regs, regs);
+	memcpy(mode_info->mode_info_block, buffer,
+		sizeof(struct vesa_mode_info));
+	mode_info->valid = true;
+	mode_info->video_mode = vesa_mode;
+	vm = &mode_info->vesa;
+	vm->x_resolution = le16_to_cpu(vm->x_resolution);
+	vm->y_resolution = le16_to_cpu(vm->y_resolution);
+	vm->bytes_per_scanline = le16_to_cpu(vm->bytes_per_scanline);
+	vm->phys_base_ptr = le32_to_cpu(vm->phys_base_ptr);
+	vm->mode_attributes = le16_to_cpu(vm->mode_attributes);
+	debug("VBE: Init complete\n");
+
+	return 0;
 }
 
 /****************************************************************************
@@ -132,6 +250,9 @@
 	/*Cleanup and exit*/
 	BE_getVGA(vga_info);
 
+	/* Useful for debugging */
+	if (0)
+		atibios_debug_mode(vga_info, &regs, vesa_mode, mode_info);
 	if (vesa_mode != -1)
 		atibios_set_vesa_mode(&regs, vesa_mode, mode_info);
 }
diff --git a/include/vbe.h b/include/vbe.h
index d405691..c5deee9 100644
--- a/include/vbe.h
+++ b/include/vbe.h
@@ -35,10 +35,14 @@
 struct __packed vbe_info {
 	char signature[4];
 	u16 version;
-	u8 *oem_string_ptr;
+	u32 oem_string_ptr;
 	u32 capabilities;
-	u16 video_mode_list[256];
+	u32 modes_ptr;
 	u16 total_memory;
+	u16 oem_version;
+	u32 vendor_name_ptr;
+	u32 product_name_ptr;
+	u32 product_rev_ptr;
 };
 
 struct __packed vesa_mode_info {
@@ -96,6 +100,7 @@
 #define VESA_GET_INFO		0x4f00
 #define VESA_GET_MODE_INFO	0x4f01
 #define VESA_SET_MODE		0x4f02
+#define VESA_GET_CUR_MODE	0x4f03
 
 struct graphic_device;
 int vbe_get_video_info(struct graphic_device *gdev);